zoukankan      html  css  js  c++  java
  • 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;
    }
    



  • 相关阅读:
    java一个字符串中出现次数最多的字符以及次数
    按要求分解字符串,输入两个数M,N;M代表输入的M串字符串,N代表输出的每串字符串的位数,不够补0。例如:输入2,8, “abc” ,“123456789”,则输出为“abc00000”,“12345678“,”90000000”
    Java 替换空格
    Java中equals()和“==”区别
    ramfs和tmpfs的区别
    C语言中的nan和inf使用
    Abp中SwaggerUI的多个接口文档配置说明
    Abp中SwaggerUI的接口说明文档配置
    Abp中SwaggerUI的接口文档添加上传文件参数类型
    Abp中自定义Exception的HttpStatusCode
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3049949.html
Copyright © 2011-2022 走看看