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 3494)