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]='\0';
        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\n",ans);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章