后缀自动机还是只会打板子,已经知道它是个什么东西了,但还是和它的构造联系不起来。。先背板子吧。
后缀自动机有一个很好的特性就是可以涵盖所有不重复的子串,我们利用这一点在它上面dp就行了;
代码参考:http://blog.csdn.net/fuxey/article/details/51050474
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int mod=2012,maxn=400010; char ss[maxn],s[maxn]; int tt[maxn],last,cur=1,cnt=1,n,len,sum[maxn],ch[maxn][10],fa[maxn],dis[maxn]; int c[maxn],q[maxn]; void add(int c,int id){ last=cur;cur=++cnt; int p=last;dis[cur]=id; for(;p&&!ch[p][c];p=fa[p])ch[p][c]=cur; if(!p)fa[cur]=1; else{ int q=ch[p][c]; if(dis[q]==dis[p]+1)fa[cur]=q; else{ int nt=++cnt;dis[nt]=dis[p]+1; memcpy(ch[nt],ch[q],sizeof(ch[0])); fa[nt]=fa[q];fa[q]=fa[cur]=nt; for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nt; } } } void rsort(){ memset(c,0,sizeof(c)); for(int i=1;i<=cnt;++i)c[dis[i]]++; for(int i=1;i<=cnt;++i)c[i]+=c[i-1]; for(int i=1;i<=cnt;++i)q[c[dis[i]]--]=i; } int main(){ while(cin>>n){ cnt=1;memset(fa,0,sizeof(fa)); memset(ch,0,sizeof(ch)); for(int i=1;i<=n;++i){ scanf("%s",ss+1); cur=1;len=strlen(ss+1); for(int j=1;j<=len;++j)add(ss[j]-'0',j); } rsort();//先排一遍序保证计算顺序没有问题,保证一个点在更新别的点之前已经被所有能到它的点更新过; memset(sum,0,sizeof(sum));memset(tt,0,sizeof(tt)); sum[1]=0;tt[1]=1; for(int i=1,j;i<=cnt;++i){ j=q[i]; for(int k=0,t;k<10;++k){ if(j==1&&(!k))continue; t=ch[j][k]; (sum[t]+=tt[j]*k+sum[j]*10)%=mod; (tt[t]+=tt[j])%=mod; //cout<<sum[t]<<' '<<tt[t]<<endl; } } int ans=0; for(int i=1;i<=cnt;++i){(ans+=sum[i])%=mod;} printf("%d\n",ans); } //system("pause"); return 0; } /* 5 101 123 09 000 1234567890 */