一道后缀自动机的算是模板题吧,可是我还是折腾了一个下午……总算对这个模板有了稍微深入的理解,debug了很久,也发现了不少的问题。现在算是基本会用后缀数组了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn=2000010;
const int sigma=26;
int n,sz;
struct state
{
state *pre,*go[sigma];
int val,cnt,flag;
void clear()
{
pre=0;val=0;cnt=0;flag=0;
memset(go,0,sizeof(go));
}
} *root,*last,st[maxn],*r[maxn];
int t[maxn];
void init()
{
sz=0;
root=last=&st[sz++];
root->clear();
}
void extend(int w)
{
state *p=last;
state *np=&st[sz++];
np->clear();
np->val=p->val+1;
np->cnt=1;
while(p && p->go[w]==0)
{
p->go[w]=np;
p=p->pre;
}
if(p==0) np->pre=root;
else
{
state *q=p->go[w];
if(q->val==p->val+1) np->pre=q;
else
{
state *nq=&st[sz++];
*nq=*q;
nq->val=p->val+1;
nq->cnt=0;
q->pre=nq;
np->pre=nq;
while(p && p->go[w]==q)
{
p->go[w]=nq;
p=p->pre;
}
}
}
last=np;
}
char s[maxn];
vector<int> v[maxn];
int main()
{
//freopen("in.txt","r",stdin);
scanf("%s",s);
int m=strlen(s);
init();
for(int i=0;i<m;i++) extend(s[i]-'a');
// for(int i=1;i<sz;i++) v[st[i].val].push_back(i);
// for(int i=m;i>=1;i--)
// for(int j=0;j<v[i].size();j++)
// {
// int x=v[i][j];
// if(st[x].pre) st[x].pre->cnt+=st[x].cnt;
// }
memset(t,0,sizeof(t));
for(int i=1;i<sz;i++) t[st[i].val]++;
for(int i=1;i<=m;i++) t[i]+=t[i-1];
for(int i=1;i<sz;i++) r[t[st[i].val]--]=&st[i];
for(int i=sz-1;i>0;i--)
{
//cout<<r[i]->cnt<<" "<<r[i]->val<<endl;
r[i]->pre->cnt+=r[i]->cnt;
}
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",s);
m=strlen(s);
for(int j=0;j<m;j++) s[j+m]=s[j];
s[2*m]=0;
state *p=root;
int len=0,ans=0;
for(int j=0;j<2*m;j++)
{
int w=s[j]-'a';
while(p && p->go[w]==0)
{
p=p->pre;len=p?p->val:0;
}
if(p==0)
{
p=root;
len=0;
continue;
}
p=p->go[w];len++;
if(len>=m)
{
state *tmp=p;
while(tmp->pre && tmp->pre->val>=m)
tmp=tmp->pre;
if(tmp->flag!=i)
{
tmp->flag=i;
//cout<<j<<" "<<tmp->val<<" "<<tmp->cnt<<endl;
ans+=tmp->cnt;
}
}
//cout<<j<<" "<<ans<<endl;
}
printf("%d\n",ans);
}
return 0;
}