首页 > 代码库 > ZOJ 3494 (AC自动机+高精度数位DP)

ZOJ 3494 (AC自动机+高精度数位DP)

题目链接:  http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3494

题目大意:给定一些被禁止的BCD码。问指定范围内不含有任何这些禁止的BCD码的数的个数。

解题思路

AC自动机部分:

首先insert这些被禁止的BCD码。

然后打一下自动机前后状态的转移的表,用BCD[i][j]表示自动机状态i时,下一个数字是j的自动机的下一个状态。

一开始我考虑最先dfs的位在自动机的位置,后来发现SB了。AC自动机有一个root状态,也就是自动机位置为0的状态,使用这个0就行了。

即f函数中dfs(len,0,true,true),每次由root状态出发,无须再考虑其它的。

 

数位DP部分:

本题的范围是高精度范围,所以需要特有的高精度写法。

麻烦的在于f(l-1),要为高精度手艹一个-1,有种偷懒的写法,不过会导致出现前导0。

所以在传统的dfs中需要增加一个前导0的判断。

方法是:追加一个bool z,

在原有的0~9基础上,单独考虑0,

if(z) 则单独dfs前导0

否则dfs正常的0,1~9照常dfs。当然还需要判断当前状态s的下一个状态BCD[s][i]是否符合要求。

然后最后就是注意一下负数mod。

 

#include "cstdio"#include "cstring"#include "queue"#include "iostream"using namespace std;#define maxp 25*105#define mod 1000000009struct Trie{    Trie *next[2],*fail;    int cnt;}pool[maxp],*root,*sz;int BCD[maxp][10],digit[205],ccnt;long long dp[205][maxp];Trie *newnode(){    Trie *ret=sz++;    memset(ret->next,0,sizeof(ret->next));    ret->fail=0;    ret->cnt=0;    return ret;}void init(){    sz=pool;    root=newnode();}void Insert(string str){    Trie *pos=root;    for(int i=0;i<str.size();i++)    {        int c=str[i]-0;        if(!pos->next[c]) pos->next[c]=newnode();        pos=pos->next[c];    }    pos->cnt++;}void getfail(){    queue<Trie *> Q;    for(int c=0;c<2;c++)    {        if(root->next[c])        {            root->next[c]->fail=root;            Q.push(root->next[c]);        }        else root->next[c]=root;    }    while(!Q.empty())    {        Trie *x=Q.front();Q.pop();        for(int c=0;c<2;c++)        {            if(x->next[c])            {                x->next[c]->fail=x->fail->next[c];                x->next[c]->cnt+=x->fail->next[c]->cnt;                Q.push(x->next[c]);            }            else x->next[c]=x->fail->next[c];        }    }}int judge(int status,int num){    Trie *pos=pool+status;    if(pos->cnt) return -1;    for(int i=3;i>=0;i--)    {        if(pos->next[(num>>i)&1]->cnt) return -1;        else pos=pos->next[(num>>i)&1];    }    return pos-pool;}void getbcd(){    for(int i=0;i<ccnt;i++)        for(int j=0;j<10;j++)            BCD[i][j]=judge(i,j);}int dfs(int len,int s,bool fp,bool z){    if(!len) return 1;    if(!fp&&dp[len][s]!=-1) return dp[len][s];    long long ret=0;    int fpmax=fp?digit[len]:9;    if(z)    {        ret+=dfs(len-1,s,fp&&digit[len]==0,true);        ret%=mod;    }    else    {        if(BCD[s][0]!=-1) ret+=dfs(len-1,BCD[s][0],fp&&digit[len]==0,false);        ret%=mod;    }    for(int i=1;i<=fpmax;i++)    {        if(BCD[s][i]!=-1) ret+=dfs(len-1,BCD[s][i],fp&&i==fpmax,false);        ret%=mod;    }    if(!fp&&!z) dp[len][s]=ret;    return ret;}int f(string str){    int len=0;    for(int i=str.size()-1;i>=0;i--)        digit[++len]=str[i]-0;    return dfs(len,0,true,true);}int main(){    //freopen("in.txt","r",stdin);    ios::sync_with_stdio(false);    int T,n;    string tt;    cin>>T;    while(T--)    {        init();        memset(dp,-1,sizeof(dp));        cin>>n;        for(int i=1;i<=n;i++)        {            cin>>tt;            Insert(tt);        }        getfail();        ccnt=sz-pool;        getbcd();        cin>>tt;        for(int i=tt.size()-1;i>=0;i--)        {            if(tt[i]>0) {tt[i]--;break;}            else {tt[i]=9;}        }        long long ans=0;        ans-=f(tt);        ans%=mod;        cin>>tt;        ans+=f(tt);        ans=(ans%mod+mod)%mod;        printf("%lld\n",ans);    }}

 

2842327neopenxZOJ 3494Accepted4656 KB210 msC++ (g++ 4.4.5)2976 B2014-10-13 17:06:35

 

 

 

ZOJ 3494 (AC自动机+高精度数位DP)