ZOJ 3494 AC自动机+数位DP

来源:互联网 发布:怎么刷新微信运动数据 编辑:程序博客网 时间:2024/05/22 11:35

题意

有一种BCD编码方案,求A到B范围内的数字的BCD编码有多少个不包含不能包含的字符串。

题解

数字范围这么大,很明显就能看出来是数位DP。基于AC自动机的数位DP使得数位DP容易了不少,因为AC自动机自带状态转移。在数位DP选取每一位的时候,基于AC自动机状态转移一下,如果转移到不能转移的状态,就直接返回-1。如果转移到合法状态,就继续DFS。唯一需要注意的就是需要大整数的减法,不过随便写写就行了,有前导0也无所谓,反正不影响数位DP。

代码

#include <iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<string>#include<set>#include<map>#include<bitset>#include<stack>#include<string>#define UP(i,l,h) for(int i=l;i<h;i++)#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)#define W(a) while(a)#define MEM(a,b) memset(a,b,sizeof(a))#define INF 0x3f3f3f3f#define LL long long#define MAXN 100010#define MOD 1000000009#define EPS 1e-10#define int LLusing namespace std;int ch[2010][10];int sz;int val[2010],f[2010];char st[30];int dig[220];int dp[210][2010];char a[210],b[210];int code[10][4]= {{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1},{0,1,0,0},{0,1,0,1},{0,1,1,0},{0,1,1,1},{1,0,0,0},{1,0,0,1}};int run(int u,int x) {    if(val[u]) {        return -1;    }    UP(i,0,4) {        u=ch[u][code[x][i]];        if(val[u]) {            return -1;        }    }    return u;}void insert() {    int u=0;    int len=strlen(st);    UP(i,0,len) {        int x=st[i]-'0';        if(!ch[u][x]) {            ch[u][x]=sz++;        }        u=ch[u][x];    }    val[u]=1;//    cout<<"u"<<u<<endl;}void getFail() {    MEM(f,0);    queue<int> q;    UP(i,0,10) {        if(ch[0][i]) {            q.push(ch[0][i]);        }    }    W(!q.empty()) {        int r=q.front();        q.pop();        UP(i,0,10) {            int u=ch[r][i];            if(!u) {                ch[r][i]=ch[f[r]][i];                continue;            }            q.push(u);            int v=f[r];            f[u]=ch[v][i];            val[u]|=val[f[u]];//            cout<<"val"<<u<<" "<<val[u]<<endl;        }    }}int dfs(int len,int u,bool first,bool up) {    if(len==0) {        if(!first)            return 1;        else            return 0;    }    if(!up&&!first&&(dp[len][u]!=-1)) {        return dp[len][u];    }    int n=up?dig[len]:9;    int ans=0;    UP(i,0,n+1) {        if(i==0&&first) {            ans=(ans+dfs(len-1,u,true,up&&i==n))%MOD;        } else {            int temp=run(u,i);            if(temp==-1) {                continue;            }            ans=(ans+dfs(len-1,temp,false,up&&i==n))%MOD;        }    }    if(!up&&!first) {        dp[len][u]=ans%MOD;    }    return ans%MOD;}int solve(char *x) {    MEM(dp,-1);    MEM(dig,0);    int len=strlen(x);    UP(i,0,len){        dig[len-i]=x[i]-'0';    }    return dfs(len+1,0,true,true);}main() {    int t;    scanf("%lld",&t);    W(t--) {        MEM(ch,0);        MEM(val,0);        sz=1;        int n;        scanf("%lld",&n);        W(n--) {            scanf("%s",st);            insert();        }        getFail();        scanf("%s%s",&a,&b);        int len=strlen(a);        DOWN(i,len,0){            if(a[i]=='0'){                a[i]='9';            }else{                a[i]--;                break;            }        }        printf("%lld\n",(solve(b)-solve(a)+MOD)%MOD);    }}/*55110011 10*/