hdu 4436 str2int (后缀自动机+dp)

题意:

给出n个串然后,求着n个串所有子串对应的数字的和是多少。

题解:

根据陈立杰的论文我们得出这样的性质,从s开始遍历自动机,走到任意一个u,那么走过的字符构成的串肯定是整个串的子串,简单来说就是从起点到某个点构成了一个子串。那么我们就可以根据这性质计算。其实我们将串对应的数组分成不同位数进行计算,类似于数位dp的思想。dp[u]表示到节点u时构成的数位对应的数字和,那么u的下个节点v有:dp[v]=(dp[u]*10+cnt[u]*j) cnt是路径数,j是u代表的数字。这样计算其实也就是相当于字典图上的数位dp。好题!但是这样算肯定wa,为什么呢?因为对于这样v可能并不是u实际的“孩子”,因为从后缀动机图可以看出及节点时有跳跃的,那么这样计算不能保证没有后效性的,那么我们可以根据len排序,然后从头开始遍历,这样就解决了这个问题了。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define B(x) (1<<(x))
void cmax(int& a,int b){ if(b>a)a=b; }
void cmin(int& a,int b){ if(b<a)a=b; }
typedef long long ll;
const int oo=0x3f3f3f3f;
const ll OO=1LL<<61;
const int MOD=2012;
const int maxn=100005;
const int maxm=200005;
const int SIZE=maxn<<1;
const int type=11;
int Next[SIZE][type],fa[SIZE],len[SIZE];
int tol,last;
char str[maxn];
int dp[SIZE],cnt[SIZE],pos[SIZE];

bool cmp(int a,int b){
    return len[a]<len[b];
}

struct SuffixAutoMaton{

    int newNode(int x){

        len[tol]=x;
        fa[tol]=-1;
        for(int i=0;i<type;i++)
            Next[tol][i]=-1;
        return tol++;
    }

    void Init(){

        tol=0;
        last=newNode(0);
    }

    void add(int k){

        int now=last;
        int end=newNode(len[now]+1);
        while(now!=-1&&Next[now][k]==-1){

            Next[now][k]=end;
            now=fa[now];
        }
        if(now==-1) fa[end]=0;
        else{

            int nxt=Next[now][k];
            if(len[nxt]==len[now]+1) fa[end]=nxt;
            else{

                int cnxt=newNode(len[now]+1);
                for(int i=0;i<type;i++)Next[cnxt][i]=Next[nxt][i];
                fa[cnxt]=fa[nxt];
                fa[nxt]=fa[end]=cnxt;
                while(now!=-1&&Next[now][k]==nxt){
                    Next[now][k]=cnxt;
                    now=fa[now];
                }
            }
        }
        last=end;
    }

    void Insert(char T[]){

        for(int i=0;T[i];i++){
            add(T[i]-'0');
        }
    }

    int calc(){

        memset(dp,0,sizeof dp);
        memset(cnt,0,sizeof cnt);
        for(int i=0;i<tol;i++)pos[i]=i;
        sort(pos,pos+tol,cmp);
        cnt[0]=1;
        for(int i=0;i<tol;i++){
            int u=pos[i];
            for(int j=0;j<type-1;j++){
                if(u==0&&j==0)continue;
                if(Next[u][j]!=-1){
                    int v=Next[u][j];
                    dp[v]=(dp[v]+(dp[u]*10%MOD+cnt[u]*j%MOD)%MOD)%MOD;
                    cnt[v]+=cnt[u];
                }
            }
        }
        int ans=0;
        for(int i=0;i<tol;i++)ans=(ans+dp[i])%MOD;
        return ans;
    }

}sam;

int main(){

    int N,ans;
    while(scanf("%d",&N)!=EOF){

        sam.Init();
        for(int i=1;i<=N;i++){

            scanf("%s",str);
            sam.Insert(str);
            sam.add(10);
        }
        ans=sam.calc();
        printf("%d\n",ans);
    }
    return 0;
}
/**
5
101
123
09
000
1234567890

*/




你可能感兴趣的:(hdu 4436 str2int (后缀自动机+dp))