CF 235C. Cyclical Quest(后缀自动机)

传送门

解题思路

  字符串(a)(b)中出现次数,一定后缀自动机了。对文本串(s)建一个后缀自动机,预处理出倍增数组和(right)集合。考虑统计答案,对于每个模式串,因为要求出所有同构,那么就先倍长这个串,然后扫的过程中要维护在后缀自动机上匹配了多少位(tmp),当(tmp>=len)时说明可以做出贡献,那么就找到一个现在节点的最高祖先满足(l_x>=len),然后把此处的(right)集合大小加入答案。但是这样会算重复,就要给计算过答案的每个状态打个标记,撤销时用栈。数组开小调了半天。,

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
const int N=2000005;
typedef long long LL;

int n,len,a[N],c[N],stk[N],top,f[N][22];
LL ans;
char s[N],t[N];
bool vis[N];

struct SAM{
	int fa[N],ch[N][28],l[N],siz[N],cnt,lst;
	void Insert(int c){
		int p=lst,np=++cnt; l[np]=l[p]+1; lst=cnt; siz[np]=1;
		for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
		if(!p) fa[np]=1;
		else {
			int q=ch[p][c];
			if(l[q]==l[p]+1) fa[np]=q;
			else {
				int nq=++cnt; l[nq]=l[p]+1;
				memcpy(ch[nq],ch[q],sizeof(ch[nq]));
				fa[nq]=fa[q]; fa[q]=fa[np]=nq;
				for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
			}
		}
	}
	void solve(){
		for(int i=1;i<=cnt;i++) c[l[i]]++;
		for(int i=1;i<=cnt;i++) c[i]+=c[i-1];
		for(int i=1;i<=cnt;i++) a[c[l[i]]--]=i;
		for(int i=cnt;i;i--) siz[fa[a[i]]]+=siz[a[i]];
		for(int i=2;i<=cnt;i++){
			int p=a[i]; f[p][0]=fa[p];
			for(int j=1;j<=20;j++)
				f[p][j]=f[f[p][j-1]][j-1];
		}
	}
}sam;

int main(){
	scanf("%s%d",s+1,&n); sam.cnt=sam.lst=1; len=strlen(s+1);
	for(int i=1;i<=len;i++) sam.Insert(s[i]-'a'+1);
	sam.solve(); int now,tmp;
	for(int i=1;i<=n;i++){
		scanf("%s",t+1); len=strlen(t+1);
		for(int j=1;j<=len;j++) t[j+len]=t[j];
		now=1; ans=0; tmp=0; top=0;
		for(int j=1;j<=len*2;j++){
			if(sam.ch[now][t[j]-'a'+1]) now=sam.ch[now][t[j]-'a'+1],tmp++;
			else {	
				for(;now && !sam.ch[now][t[j]-'a'+1];now=sam.fa[now]);
				if(!now) now=1,tmp=0;
				else tmp=sam.l[now]+1,now=sam.ch[now][t[j]-'a'+1];
			}
			if(tmp>=len) {
				int zz=now;
				for(int k=20;k>=0;k--)
					if(f[zz][k] && sam.l[f[zz][k]]>=len) zz=f[zz][k];
				if(vis[zz]) continue; vis[zz]=1; stk[++top]=zz;
				ans+=sam.siz[zz];
			}
		}
		while(top) vis[stk[top--]]=0;
		printf("%lld
",ans); 
	}
	return 0;
}	
原文地址:https://www.cnblogs.com/sdfzsyq/p/10454989.html