zoukankan      html  css  js  c++  java
  • 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 1000000009
    struct 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
    ",ans);
        }
    }
    2842327 neopenx ZOJ 3494 Accepted 4656 KB 210 ms C++ (g++ 4.4.5) 2976 B 2014-10-13 17:06:35

     

     

     

  • 相关阅读:
    【LeetCode】17. Letter Combinations of a Phone Number
    【LeetCode】16. 3Sum Closest
    【LeetCode】15. 3Sum 三个数和为0
    【LeetCode】14. Longest Common Prefix 最长前缀子串
    【LeetCode】13. Roman to Integer 罗马数字转整数
    【LeetCode】12. Integer to Roman 整型数转罗马数
    【LeetCode】11. Container With Most Water
    【LeetCode】10. Regular Expression Matching
    Models of good programmer
    RSA Algorithm
  • 原文地址:https://www.cnblogs.com/neopenx/p/4022659.html
Copyright © 2011-2022 走看看