CF235C Cyclical Quest 题解


题面

循环同构的话很容易想到把串延长一倍,跑的时候找所有长度为 \(n\) 的公共子串的出现次数即可。

点击查看代码
const int N=3e6+13;
char s[N<<1];
int nxt[N<<1],len[N<<1],ptot=1,lastpos=1,cnt[N<<1];
std::vector son[N<<1],zrzak;
inline void clear(){son[1].resize(26),zrzak.resize(26);}
inline int newpos(std::vector nson,int nlen){return len[++ptot]=nlen,std::swap(son[ptot],nson),ptot;}
inline void insert(int c){
	int p=lastpos,u=newpos(zrzak,len[p]+1);cnt[u]=1;
	while(p&&!son[p][c]) son[p][c]=u,p=nxt[p];
	lastpos=u;
	if(!p) return nxt[u]=1,void();
	int d=son[p][c];
	if(len[d]==len[p]+1) nxt[u]=d;
	else{
		int v=newpos(son[d],len[p]+1);
		nxt[v]=nxt[d],nxt[u]=nxt[d]=v;
		while(p&&son[p][c]==d) son[p][c]=v,p=nxt[p];
	}
}
bool vis[N<<1];
std::vector G[N<<1];
void dfs(int u){for(auto v:G[u])dfs(v),cnt[u]+=cnt[v];}
int main(){
	clear();
	read(s+1);int n=strlen(s+1);
	for(int i=1;i<=n;++i) insert(s[i]-'a');
	for(int i=2;i<=ptot;++i) G[nxt[i]].pb(i);
	dfs(1);
	int q;read(q);
	while(q--){
		std::queue Q;
		read(s+1);n=strlen(s+1);
		for(int i=1;i<=n;++i) s[i+n]=s[i];
		ll ans=0;
		for(int i=1,now=1,l=0;i<(n<<1);++i){
			int c=s[i]-'a';
			while(now&&!son[now][c]) now=nxt[now],l=len[now];
			if(now&&son[now][c]) now=son[now][c],++l;
			if(l>=n){
				while(len[nxt[now]]>=n) now=nxt[now];
				if(!vis[now]) ans+=cnt[now],vis[now]=1,Q.push(now);
			}
		}
		println(ans);
		while(!Q.empty()) vis[Q.front()]=0,Q.pop();
	}
	return 0;
}