CF235C Cyclical Quest

题意

显然先把\(S\)塞进\(SAM\)中,之后处理每个询问。

对于一个询问,我们自然不能枚举所有的循环串,于是我们考虑在匹配的过程中删去首字符,加入尾字符。

先匹配好,求一波答案。之后开始删一个首字符,加一个尾字符,之后再统计,直到所有串统计完。

维护当前在哪个节点\(now\)和匹配的长度\(len\)

删一个首字符:
\(len--\)
假如\(len=len_{fa_{now}}\),就向上跳,使\(now=fa_{now}\)

添一个尾字符:
一直跳,直到\(now\)有这个字符的出边,中途跳一次令\(len=len_{now}\)

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int n,Q,cnt,tim;
int head[maxn<<1];
char s[maxn];
struct edge{int to,nxt;}e[maxn<<2];
struct SAM
{
	int last,tot;
	int fa[maxn<<1],len[maxn<<1],cnt[maxn<<1],vis[maxn<<1];
	int ch[maxn<<1][30];
	inline void init(){last=tot=1;}
	inline void add(int c)
	{
		int now=++tot;cnt[now]=1;len[now]=len[last]+1;
		int p=last;last=now;
		while(p&&!ch[p][c])ch[p][c]=now,p=fa[p];
		if(!p){fa[now]=1;return;}
		int q=ch[p][c];
		if(len[q]==len[p]+1)fa[now]=q;
		else
		{
			int nowq=++tot;len[nowq]=len[p]+1;
			memcpy(ch[nowq],ch[q],sizeof(ch[q]));
			fa[nowq]=fa[q];fa[q]=fa[now]=nowq;
			while(p&&ch[p][c]==q)ch[p][c]=nowq,p=fa[p];
		}
	}
}sam;
inline void add(int u,int v)
{
	e[++cnt].nxt=head[u];
	head[u]=cnt;
	e[cnt].to=v;
}
void dfs(int x)
{
	for(int i=head[x];i;i=e[i].nxt)
		dfs(e[i].to),sam.cnt[x]+=sam.cnt[e[i].to];
}
inline int solve(char* s)
{
	tim++;
	int len=strlen(s+1),ans=0,now=1,nowlen=0;
	for(int i=1;i<=len;i++) 
	{
		int c=s[i]-'a';
		while(now>1&&!sam.ch[now][c])now=sam.fa[now],nowlen=sam.len[now];
		if(sam.ch[now][c])now=sam.ch[now][c],nowlen++;
	}
	if(nowlen==len&&sam.vis[now]!=tim)sam.vis[now]=tim,ans+=sam.cnt[now];
	for(int i=1;i<len;i++)
	{
		int c=s[i]-'a';
		while(now>1&&!sam.ch[now][c])now=sam.fa[now],nowlen=sam.len[now];
		if(sam.ch[now][c])now=sam.ch[now][c],nowlen++;
		if(nowlen>len&&(--nowlen)==sam.len[sam.fa[now]])now=sam.fa[now];
		if(nowlen==len&&sam.vis[now]!=tim)sam.vis[now]=tim,ans+=sam.cnt[now];
	}
	return ans;
}
int main()
{
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	scanf("%s",s+1);n=strlen(s+1);
	sam.init();
	for(int i=1;i<=n;i++)sam.add(s[i]-'a');
	for(int i=2;i<=sam.tot;i++)add(sam.fa[i],i);
	dfs(1);
	scanf("%d",&Q);
	while(Q--)
	{
		scanf("%s",s+1);
		printf("%d\n",solve(s));
	}
	return 0;
} 
posted @ 2019-12-20 20:03  nofind  阅读(123)  评论(0编辑  收藏  举报