Codeforces 1483F

Codeforces 题目传送门 & 洛谷题目传送门

一道 ACAM 的 hot tea

首先建出 ACAM。考虑枚举长串,以及短串在长串中出现的最后位置 (j),这个复杂度显然是 (mathcal O(sum|s_i|)) 的不会出问题。那么显然只有以 (s_{i,j}) 为结尾的、长度最长的字符串才有可能被统计进答案,否则就不满足题目中的条件了,而这个字符串,显然就是 (s_{i,j}) 对应位置在 fail 树上向上跳得到的第一个是某个字符串结尾的位置所对应的字符串,这个可以通过对 fail 树进行一遍 DFS 求出。

其次,仔细想想就会发现这些字符串也并不是所有都真的符合条件,如果我们把这一个个字符串看作一个个框,那么如果一个框被另一个框完全包含,那显然也是不合法的,这个可以通过记录个啥数组然后线性扫一遍把这些不合法的排除掉。但是再即便是排除掉这些不合法的字符串之后也有可能出现不合法,或者同一字符串被重复统计的情况,因为对于一个未被排除掉的字符串 (s_i[l...r]),有可能存在它的另一个出现位置 (s_i[l'...r']),满足 (s_i[l'...r']) 不是以 (s_{i,r'}) 结尾的长度最长的符合要求的字符串,或者是以 (s_{i,r'}) 结尾的长度最长的符合要求的字符串但被另外一个框完全包含。怎么 check 这样的情况呢?好办,拿个 map 记录一下所有字符串在 (s_i) 中被统计的次数,然后在 map 里面扫描一遍看所有字符串 (s')(s_i) 中出现次数是否等于其被统计的次数,如果是则答案加 (1),否则说明 (s') 肯定有被排除掉的情况,就不能产生贡献了。

时间复杂度 (|S|log|S|)

const int MAXN=1e6; 
int n,ch[MAXN+5][28],ncnt=0,fail[MAXN+5],ed[MAXN+5],ps[MAXN+5];
string s[MAXN+5];
void insert(string s,int id){
	int cur=0;
	for(int i=0;i<s.size();i++){
		if(!ch[cur][s[i]-'a']) ch[cur][s[i]-'a']=++ncnt;
		cur=ch[cur][s[i]-'a'];
	} ed[id]=cur;ps[cur]=id;
}
int hd[MAXN+5],to[MAXN+5],nxt[MAXN+5],ec=0,bgt[MAXN+5],edt[MAXN+5],tim;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
void getfail(){
	queue<int> q;
	for(int i=0;i<26;i++) if(ch[0][i]) q.push(ch[0][i]);
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=0;i<26;i++){
			if(ch[x][i]) fail[ch[x][i]]=ch[fail[x]][i],q.push(ch[x][i]);
			else ch[x][i]=ch[fail[x]][i];
		}
	}
	for(int i=1;i<=ncnt;i++) adde(fail[i],i);
}
原文地址:https://www.cnblogs.com/ET2006/p/Codeforces-1483F.html