题意
给出一个字符串s1和q个询问,每个询问给出一个字符串s2,问这个询问的字符串的所有不同的周期串在s1中出现的次数的和。
分析
对于s1建后缀自动机。对于询问的每个字符串s2,我们按照处理循环串的方法,将它长度乘二再复制一遍。然后根据s2在自动机上跑,当长度len=n的时候,就更新答案。因为要求统计的是不同的周期串,所以对于每个状态都需要打一个vis标记。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std;
const int maxn=2e6+;
char s[maxn];
struct state{
int len,link;
int next[];
}st[*maxn];
int last,cur,sz,Q,n;
int cnt[*maxn],c[*maxn],vis[*maxn];
void init(){
sz=;
last=cur=;
st[].link=-;
st[].len=;
}
void build_sam(int c){
cur=sz++;
st[cur].len=st[last].len+;
cnt[cur]=;
int p;
for(p=last;p!=-&&st[p].next[c]==;p=st[p].link){
st[p].next[c]=cur;
}
if(p==-)
st[cur].link=;
else{
int q=st[p].next[c];
if(st[q].len==st[p].len+)
st[cur].link=q;
else{
int clone=sz++;
st[clone].len=st[p].len+;
st[clone].link=st[q].link;
for(int i=;i<;i++)
st[clone].next[i]=st[q].next[i];
for(;p!=-&&st[p].next[c]==q;p=st[p].link){
st[p].next[c]=clone;
}
st[cur].link=st[q].link=clone;
}
}
last=cur;
}
int cmp(int a,int b){
return st[a].len>st[b].len;
}
int solve(int id){
int res=;
int u=,len=;
for(int i=;i<*n-;i++){
int c=s[i]-'a';
while(u!=-&&(st[u].next[c]==))
u=st[u].link,len=st[u].len;
if(u==-)
u=,len=;
else{
u=st[u].next[c];
len++;
if(len>=n&&vis[u]!=id){
res+=cnt[u];
vis[u]=id;
}
while(n!=&&st[u].link!=-&&st[st[u].link].len>=n-)
u=st[u].link,len=st[u].len;
}
}
return res;
} int main(){
scanf("%s",s);
n=strlen(s);
init();
for(int i=;i<n;i++)
build_sam(s[i]-'a');
for(int i=;i<sz;i++)
c[i]=i;
sort(c,c+sz,cmp);
for(int i=;i<sz;i++){
int o=c[i];
if(st[o].link!=-){
cnt[st[o].link]+=cnt[o];
}
} scanf("%d",&Q);
for(int i=;i<=Q;i++){
// memset(vis,0,sizeof(vis));
scanf("%s",s);
n=strlen(s);
for(int j=;j<n;j++)
s[j+n]=s[j];
int res=solve(i);
printf("%d\n",res);
}
return ;
}