zoukankan      html  css  js  c++  java
  • zoj3494 BCD Code(AC自动机+数位dp)

    Binary-coded decimal (BCD) is an encoding for decimal numbers in which each digit is represented by its own binary sequence. To encode a decimal number using the common BCD encoding, each decimal digit is stored in a 4-bit nibble:

    Decimal:    0     1     2     3     4     5     6     7     8     9
    BCD:     0000  0001  0010  0011  0100  0101  0110  0111  1000  1001
    

    Thus, the BCD encoding for the number 127 would be:

     0001 0010 0111
    

    We are going to transfer all the integers from A to B, both inclusive, with BCD codes. But we find that some continuous bits, named forbidden code, may lead to errors. If the encoding of some integer contains these forbidden codes, the integer can not be transferred correctly. Now we need your help to calculate how many integers can be transferred correctly.

    Input

    There are multiple test cases. The first line of input is an integer T ≈ 100 indicating the number of test cases.

    The first line of each test case contains one integer N, the number of forbidden codes ( 0 ≤ N ≤ 100). Then N lines follow, each of which contains a 0-1 string whose length is no more than 20. The next line contains two positive integers A and B. Neither A or B contains leading zeros and 0 < A ≤ B < 10200.

    Output

    For each test case, output the number of integers between A and B whose codes do not contain any of the N forbidden codes in their BCD codes. For the result may be very large, you just need to output it mod 1000000009.

    Sample Input

    3
    1
    00
    1 10
    1
    00
    1 100
    1
    1111
    1 100
    

    Sample Output

    3
    9
    

    98

    题意:给出一些模式串,给出一个范围[A,B],求出区间内有多少个数,写成BCD之后,不包含模式串。

    思路:先用AC自动机存下不符合的节点,然后预处理出bcd[i][j]表示ac自动机节点i走j这个数后的节点编号或者-1,然后用dp[i][j]表示前i位,当前ac节点为j的方案数。

    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<string>
    #include<bitset>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef long double ldb;
    #define inf 99999999
    #define pi acos(-1.0)
    #define maxn 300050
    #define maxnode 2050
    #define MOD 1000000009
    int bcd[maxnode][11]; //bcd[i][j]表示ac自动机状态i走j步后的状态
    
    struct trie{
        int sz,root,val[maxnode],next[maxnode][2],fail[maxnode];
        int q[11111];
        void init(){
            int i;
            sz=root=0;
            val[0]=0;
            for(i=0;i<2;i++){
                next[root][i]=-1;
            }
        }
        void charu(char *s){
            int i,j,u=0;
            int len=strlen(s);
            for(i=0;i<len;i++){
                int c=s[i]-'0';
                if(next[u][c]==-1){
                    sz++;
                    val[sz]=0;
                    next[u][c]=sz;
                    u=next[u][c];
                    for(j=0;j<2;j++){
                        next[u][j]=-1;
                    }
                }
                else{
                    u=next[u][c];
                }
            }
            val[u]=1;
        }
    
        void build(){
            int i,j;
            int front,rear;
            front=1;rear=0;
            for(i=0;i<2;i++){
                if(next[root][i]==-1 ){
                    next[root][i]=root;
                }
                else{
                    fail[next[root][i] ]=root;
                    rear++;
                    q[rear]=next[root][i];
                }
            }
            while(front<=rear){
                int x=q[front];
                if(val[fail[x]])        //!!!!!
                    val[x]=1;
                front++;
                for(i=0;i<2;i++){
                    if(next[x][i]==-1){
                        next[x][i]=next[fail[x] ][i];
                    }
                    else{
                        fail[next[x][i] ]=next[fail[x] ][i];
                        rear++;
                        q[rear]=next[x][i];
                    }
    
                }
            }
        }
    }ac;
    
    int change(int jiedian,int num)
    {
        int i,j,len=0;
        int shu[10];
        while(num){
            shu[++len]=num%2;
            num/=2;
        }
        while(len<4)shu[++len]=0;
        for(i=4;i>=1;i--){
            if(ac.val[ac.next[jiedian][shu[i] ] ]==1 )return -1;
            else jiedian=ac.next[jiedian][shu[i] ];
        }
        return jiedian;
    }
    
    void pre_init()
    {
        int i,j;
        for(i=0;i<=ac.sz;i++){
            for(j=0;j<=9;j++){
                bcd[i][j]=change(i,j);
            }
        }
    }
    
    
    int wei[300];
    ll dp[300][maxnode];
    
    ll dfs(int pos,int jiedian,int lim,int zero)
    {
        int i,j;
        if(pos==-1)return 1;
        if(lim==0 && zero==0 && dp[pos][jiedian]!=-1){ //这里和下面同理,也不要省略zero==0
            return dp[pos][jiedian];
        }
        int ed=lim?wei[pos]:9;
        ll ans=0;
        for(i=0;i<=ed;i++){
            if(i==0){
                if(zero){
                    ans+=dfs(pos-1,jiedian,0,1);
                    ans%=MOD;
                }
                else{
                    if(bcd[jiedian][0]!=-1){
                        ans+=dfs(pos-1,bcd[jiedian][0],lim&&i==ed,0);
                        ans%=MOD;
                    }
                }
                continue;
            }
            if(bcd[jiedian][i]!=-1){
                ans+=dfs(pos-1,bcd[jiedian][i],lim&&i==ed,0);
                ans%=MOD;
            }
        }
        if(lim==0 && zero==0 ){  //这里要注意,不能写成if(lim==0)dp[pos][jiedian]=ans;因为zero不为0的话,即最高位还没有确定,那么可能后面几位都可以跳过去,
            dp[pos][jiedian]=ans; //即可以把0跳过,但是对于最高位确定的情况下,后面不管加什么数都不能跳过去,即使是0也要在ac自动机上走0这个数.
        }
        return ans;
    }
    
    
    ll cal(char *s)
    {
        int i,j,len;
        len=strlen(s);
        for(i=0;i<len;i++){
            wei[i]=s[len-1-i]-'0';
        }
        return dfs(len-1,0,1,1);
    }
    
    
    char s1[300],s2[300],s[30];
    int main()
    {
        int n,m,i,j,T,len1,len2;
        scanf("%d",&T);
        while(T--)
        {
            ac.init();
            scanf("%d",&n);
            for(i=1;i<=n;i++){
                scanf("%s",s);
                ac.charu(s);
            }
            ac.build();
            pre_init();
            scanf("%s",s1);
            len1=strlen(s1);
            reverse(s1,s1+len1);
            for(i=0;i<len1;i++){  //这里算的是(l,r],所以先要把s1的数减去1
                if(s1[i]-'0'>0){
                    s1[i]--;break;
                }
                else{
                    s1[i]='9';
                }
            }
            memset(dp,-1,sizeof(dp));
            ll ans=0;
            if(s1[len1-1]=='0')len1-=1;
            s1[len1]='';
            reverse(s1,s1+len1);
            ans-=cal(s1);
            ans%=MOD;
            scanf("%s",s2);
            ans+=cal(s2);
            ans%=MOD;
            if(ans<0){
                ans=(ans+MOD)%MOD;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    


  • 相关阅读:
    享元模式及php实现
    共享内存
    LCD触屏驱动
    I2C驱动
    C++ & java小结
    使用GlobalKey启动APP
    socketpair通信
    inotify和epoll
    C语言之二叉树
    灯光系统
  • 原文地址:https://www.cnblogs.com/herumw/p/9464501.html
Copyright © 2011-2022 走看看