zoj 3494

数位dp+ac自动机

 

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <queue>

#define mod 1000000009

#define N 2010

typedef long long ll;

using namespace std;

char s[210];

int next[N][2],nextd[N][10],pos,flag[N],fail[N];

ll dp[210][N];



int newnode(){

    memset(next[pos],0,sizeof(next[pos]));

    memset(nextd[pos],0,sizeof(nextd[pos]));

    flag[pos]=fail[pos]=0;

    return pos++;

}



void insert(){

    int p=0,i;

    for(i=0;s[i];i++){

        int k=s[i]-'0';

        p=next[p][k]?next[p][k]:next[p][k]=newnode();

    }

    flag[p]=1;

}



void makefail(){

    queue<int>q;

    q.push(0);

    while(!q.empty()){

        int u=q.front();

        q.pop();

        for(int i=0;i<2;i++){

            int v=next[u][i];

            if(v==0) next[u][i]=next[fail[u]][i];

            else q.push(v);

            if(u&&v){

                fail[v]=next[fail[u]][i];

                flag[v]|=flag[fail[v]];

            }

        }

    }

}



void makenext(){

    int tem,i,j,k;

    for(i=0;i<pos;i++){

        for(j=0;j<10;j++){

            if(flag[i]==0){

                tem=i;               //在这wa死了

                for(k=3;k>=0;k--){   //在这wa死了

                    if(j&(1<<k)){

                        tem=next[tem][1];

                    }

                    else{

                        tem=next[tem][0];

                    }

                    if(flag[tem]==1)break;

                }

                if(k==-1) nextd[i][j]=tem;

                else nextd[i][j]=-1;

            }

            else nextd[i][j]=-1;

        }

    }

}



void pre(){

    int len=strlen(s),i,j;

    for(i=0;i<len;i++) if(s[i]!='0')break;

    if(i==0)return;

    for(j=i,i=0;j<len;j++,i++) s[i]=s[j];

    s[i]='\0';

}



void minus_one(){

    int len=strlen(s),i;

    for(i=len-1;i>=0;i--){

        if(s[i]>'0'){

            s[i]--;

            return ;

        }

        else s[i]='9';

    }

}



/*ll dfs(int pos,int sta,int pre,int doing){    //不需要存储前面都是0的解,因为只会用到一次,dp少开一维

    if(!s[pos]) return 1;

    if(!doing && pre && dp[pos][sta]!=-1) return dp[pos][sta];

    ll ans=0;

    int i,end;



    if(doing)end=s[pos]-'0'; else end=9;

    if(pre==0) ans=dfs(pos+1,0,0,0)%mod;

    else{

        if(nextd[sta][0]!=-1) ans=(ans+dfs(pos+1,nextd[sta][0],1,(doing && (i==end))))%mod;

    }

    for(i=1;i<=end;i++){

        if(nextd[sta][i]==-1)continue;

        ans=(ans+dfs(pos+1,nextd[sta][i],1,(doing && (i==end))))%mod;

    }

    if(!doing && pre){

        dp[pos][sta]=ans;

    }

    return ans;

}



ll solve(){

    memset(dp,-1,sizeof(dp));

    return dfs(0,0,0,1);

}*/



ll dfs(int pos,int sta,int first,int doing){

    if(!s[pos]) return 1;

    if(!doing && !first && dp[pos][sta]!=-1) return dp[pos][sta];

    ll ans=0;

    int i,end;

    if(doing)end=s[pos]-'0'; else end=9;



    for(i=first;i<=end;i++){

        if(nextd[sta][i]==-1)continue;

        //ans=(ans+dfs(pos+1,nextd[sta][i],0,(doing && (i==end))))%mod;

        ans+=dfs(pos+1,nextd[sta][i],0,(doing && (i==end)));

        if(ans>=mod)ans-=mod;

    }

    if(!doing && !first){

        dp[pos][sta]=ans;

    }

    return ans;

}



ll solve(){

    ll ans=0;

    memset(dp,-1,sizeof(dp));

    for(int i=0;s[i];i++){    //这样写是枚举长度,注意这里没有算上0

        //ans=(ans+dfs(i,0,1,i==0))%mod;

        ans+=dfs(i,0,1,i==0);

        if(ans>=mod) ans-=mod;

    }

    return ans;

}



int main(){

    int t,T,n,i,j;

    scanf("%d",&T);

    for(t=1;t<=T;t++){

        scanf("%d",&n);

        pos=0,newnode();

        for(i=1;i<=n;i++){

            scanf("%s",s);

            insert();

        }

        makefail();

        makenext();

        scanf("%s",s);

        pre();

        minus_one();

        ll ans1=solve();

        scanf("%s",s);

        pre();

        ll ans2=solve();



        printf("%lld\n",(ans2-ans1+mod)%mod);

    }

    return 0;

}


 


你可能感兴趣的:(ZOJ)