首页 > 其他分享 >[题解]CF1223F Stack Exterminable Arrays

[题解]CF1223F Stack Exterminable Arrays

时间:2023-10-24 18:55:48浏览次数:43  
标签:Trie int 题解 ll 会加 Arrays 编号 CF1223F 节点

CCF 出的原题观摩一下。

思路

首先可以用一个 Trie 来维护。

在这里对本文中的一些变量做一下说明。

  1. \(p\) 表示当前维护的 Trie 中,指向的元素编号。

  2. \(t_i\) 表示在 Trie 中编号为 \(i\) 的元素在原序列中的值。

  3. \(f_i\) 表示在 Trie 中编号为 \(i\) 的元素在 Trie 中的父节点。

  4. \(v_i\) 表示在 Trie 中编号为 \(i\) 被遍历的次数。

考虑每一次将一个数 \(a_i\) 加入 Trie 的时候需要做什么操作。

如果当前在 Trie 中指向的节点 \(t_p\) 与 \(a_i\) 相等,说明可以进行合并, 那么直接将 \(p\) 跳到 \(f_p\) 即可;否则需要新开一个节点 \(v\),接在 \(p\) 的下方,并将 \(p\) 更新到 \(v\) 上。

然后在更新 \(p\) 之后,要将 \(v_p\) 加 \(1\)。

考虑如何统计答案。发现点 \(p\) 被遍历过 \(2\) 次时,答案会加 \(1\);\(3\) 次,答案会加 \(2\);以此类推。

这是因为当 \(v_p > 1\) 时,说明 \(p\) 节点已经可以被合并 \(v_p - 1\) 次了,所以直接加 \(v_p - 1\) 即可。

注意:在代码中为了优美,将 \(v_p\) 初值设为了 \(-1\)。

但是用普通的 Trie 显然是过不了的,因为 Trie 的空间复杂度在本题中会变为 \(\Theta(n^2)\),所以直接开一个 umap 即可。

复杂度为 \(\Theta(n \log n)\),实测跑得飞快。

code

#include <bits/stdc++.h>
#define re register
#define ll long long

using namespace std;

const int N = 3e5 + 10;
int T,n,p,idx;
ll ans;
int arr[N];

struct node{
	ll val;
	int u,fa;
	unordered_map<int,int> son;
}tr[N];

inline int read(){
	int r = 0,w = 1;
	char c = getchar();
	while (c < '0' || c > '9'){
		if (c == '-') w = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9'){
		r = (r << 3) + (r << 1) + (c ^ 48);
		c = getchar();
	}
	return r * w;
}

inline void solve(){
	ans = 0;
	p = idx = 1;
	n = read();
	for (re int i = 1;i <= n;i++){
		tr[i].val = tr[i].u = tr[i].fa = 0;
		tr[i].son.clear();
		arr[i] = read();
	}
	for (re int i = 1;i <= n;i++){
		if (arr[i] == tr[p].u) p = tr[p].fa;
		else{
			int v;
			if (!tr[p].son.count(arr[i])){
				tr[p].son[arr[i]] = v = ++idx;
				tr[v] = {-1,arr[i],p};
			}
			else v = tr[p].son[arr[i]];
			p = v;
		}
		tr[p].val++;
		ans += tr[p].val;
	}
	printf("%lld\n",ans);
}

int main(){
	T = read();
	while (T--) solve();
	return 0;
}

标签:Trie,int,题解,ll,会加,Arrays,编号,CF1223F,节点
From: https://www.cnblogs.com/WaterSun/p/CF1223F.html

相关文章

  • Stack Exterminable Arrays
    prologueCSPS2023T2原题,什么成分我就不多说了。(考场上没写出来的菜鱼,想到栈了然后算法假了,寄)analysis(虽然这样不对,但是我还是想撇一下我的错解)错解我们开一个栈,每一个元素进来看和栈顶元素一样不一样,如果不一样,就入栈,否则就\(ans+cnt\),\(cnt\)表示我们的栈有多少次是空......
  • CSP-S 2023 题解
    CSP-S2023题解游记打得非常烂。。。也是一个经验的总结吧:T1.密码锁(lock)似乎也没什么好讲的,直接模拟枚举每一种情况即可。放上我的考场代码。#include<bits/stdc++.h>usingnamespacestd;intn,a[10][8],b[2][90][8],ans=0,len,l;intread(){intx=0,f=1;char......
  • Codeforces 1862G 题解
    传送门题解因为有这个操作:将序列\(a\)加上\(\{n,n-1,\cdots,1\}\),考虑差分。那么显然每次操作会将差分数组中的每个元素减去\(1\),如果差分数组中有\(0\),就会把\(0\)删除。所以可以发现差分数组中剩下的一定是操作前的最大值。由于操作后最大值还是最大值,最小值仍......
  • CF1777A题解
    分析发现操作2不会改变数的奇偶性,故无视。那么操作就是单纯删一个数。对于一个连续出现\(x\)个奇偶性相同的数的序列,需要删\(x-1\)个数(因为只剩下一个数就不会和相邻的数奇偶性相同了)。觉得找序列太麻烦,观察到连续出现\(x\)个奇偶性相同的数的序列有\(x-1\)个不......
  • CF1523D Love-Hate 题解
    抽象化题意:一共有\(m\)个元素,给定\(n\)个集合,每个集合的元素不超过\(15\)个,求出一个元素个数最多的集合\(S\)是至少\(\lceil\dfrac{n}{2}\rceil\)个集合的子集。其中$p$$(1\len\le2\cdot10^5,1\lep\lem\le60)$我们先假设\(limit=\lceil\dfrac......
  • 2023级HAUT新生周赛题解汇总
    2023级HAUT新生周赛(零)熟悉周赛规则专场:2023级HAUT新生周赛(一)@21级学长专场(张子豪,张鑫,李昊阳):2023级HAUT新生周赛(二)@曹瑞峰专场:2023级HAUT新生周赛(三)@22级学姐专场(杨焱,刘振歌,周欣滢):2023级HAUT新生周赛(四)@牛浩然专场:2023级HAUT新生周赛(五)@陈兰锴专场:......
  • JWT Tool:针对 JSON Web Tokens 的测试工具题解JWT cracking
    什么是JWT?JWT是JSONWebToken的缩写,它是一串带有声明信息的字符串,由服务端使用加密算法对信息签名,以保证其完整性和不可伪造性。Token里可以包含所有必要的信息,这样服务端就无需保存任何关于用户或会话的信息了。JWT可用于身份认证,会话状态维持以及信息交换等任务。JWT由三部分......
  • CSP20230917-3 梯度求解 题解
    〇、题目太长了懒得写。简单来说就是求对于一个后缀表达式,每个询问给出一个下标和一些值,求以该下标变量为自变量其它变量为常数时的偏导数。一、思路考虑直接对于表达式建出表达式树。建树的过程比较直接:每次栈里面放节点编号,遇到符号就取出当前栈顶两个节点作为子节点。每......
  • Codeforces Round 886 (Div. 4) 题解
    link我为什么还要vpdiv4场。。。A直接找最大的两个判断一下。voidsolve(){ inta[3]; cin>>a[0]>>a[1]>>a[2]; sort(a,a+3); if(a[2]+a[1]>=10)cout<<"YES\n"; elsecout<<"NO\n";}B按照题目意思模拟。voidsolv......
  • P3657 题解
    是不是有点恶意评分了题目链接Sol看完题目就想到了这个题。这道题同样是求线段,不过这个加了点限制,发现一个点最多连4条边出去,暴力连边的复杂度是正确的,于是就把这题变成黄了。利用刚刚那道题的trick,把边按左端点排序后右端点的LIS就是答案。这里给一个更方便的做法,不用......