后缀自动机还是只会打板子,已经知道它是个什么东西了,但还是和它的构造联系不起来。。先背板子吧。

后缀自动机有一个很好的特性就是可以涵盖所有不重复的子串,我们利用这一点在它上面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
*/

 

posted on 2018-01-30 20:59  湮灭之瞳  阅读(146)  评论(0编辑  收藏  举报