首页 > 代码库 > ZOJ 3494 BCD Code (AC自己主动机 + 数位DP)

ZOJ 3494 BCD Code (AC自己主动机 + 数位DP)

题目链接:BCD Code


解析:n个病毒串。问给定区间上有多少个转换成BCD码后不包括病毒串的数。

很奇妙的题目。

经典的 AC自己主动机 + 数位DP 的题目。
首先使用AC自己主动机,得到bcd[i][j]表示状态i,加了数字j以后到达的状态。为-1表示不能转移
然后就是数位DP了

注意记录为0的状态



AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

struct Trie{
    int next[2010][2], fail[2010];
    bool end[2010];
    int root, L;
    int newnode(){
        for(int i=0; i<2; i++)  next[L][i] = -1;
        end[L++] = false;
        return L-1;
    }
    void init(){
        L = 0;
        root = newnode();
    }
    void insert(char buf[]){
        int len = strlen(buf);
        int now = root;
        for(int i=0; i<len; i++){
            if(next[now][buf[i] - ‘0‘] == -1)
                next[now][buf[i] - ‘0‘] = newnode();
            now = next[now][buf[i] - ‘0‘];
        }
        end[now] = true;
    }
    void build(){
        queue<int> Q;
        fail[root] = root;
        for(int i=0; i<2; i++)
            if(next[root][i] == -1) next[root][i] = root;
            else{
                fail[ next[root][i] ] = root;
                Q.push(next[root][i]);
            }
        while(!Q.empty()){
            int now = Q.front();
            Q.pop();
            if(end[ fail[now] ]) end[now] = true;
            for(int i=0; i<2; i++)
                if(next[now][i] == -1)  next[now][i] = next[ fail[now] ][i];
                else{
                    fail[ next[now][i] ] = next[ fail[now] ][i];
                    Q.push(next[now][i]);
                }
        }
    }
};

Trie ac;
char buf[210];

int bcd[2010][10];
int change(int pre, int num){
    if(ac.end[pre]) return -1;
    int cur = pre;
    for(int i=3; i>=0; i--){
        if(ac.end[ac.next[cur][(num>>i)&1]]) return -1;
        cur = ac.next[cur][(num>>i)&1];
    }
    return cur;
}
void pre_init(){
    for(int i=0; i<ac.L; i++)
        for(int j=0; j<10; j++)
            bcd[i][j] = change(i, j);
}
const int MOD = 1000000009;
long long dp[210][2010];
int bit[210];

long long dfs(int pos, int s, bool flag, bool z){
    if(pos == -1) return 1;
    if(!flag && dp[pos][s] != -1) return dp[pos][s];
    long long ans = 0;
    if(z){
        ans += dfs(pos-1, s, flag && bit[pos] == 0, true);
        ans %= MOD;
    }
    else{
        if(bcd[s][0] != -1) ans += dfs(pos-1, bcd[s][0], flag && bit[pos] == 0, false);
        ans %= MOD;
    }
    int _end = (flag ? bit[pos] : 9);
    for(int i=1; i<=_end; i++){
        if(bcd[s][i] != -1){
            ans += dfs(pos-1, bcd[s][i], flag && i == _end, false);
            ans %= MOD;
        }
    }
    if(!flag && !z) dp[pos][s] = ans;
    return ans;
}

long long calc(char s[]){
    int len = strlen(s);
    for(int i=0; i<len; i++) bit[i] = s[len-1 - i] - ‘0‘;
    return dfs(len-1, 0, true, true);
}

int main(){
    #ifdef sxk
        freopen("in.txt", "r", stdin);
    #endif // sxk
    int T;
    int n;
    scanf("%d", &T);
    while(T--){
        ac.init();
        scanf("%d", &n);
        for(int i=0; i<n; i++){
            scanf("%s", buf);
            ac.insert(buf);
        }
        ac.build();
        pre_init();
        memset(dp, -1, sizeof(dp));
        int ans = 0;
        scanf("%s", buf);
        int len = strlen(buf);
        for(int i=len-1; i>=0; i--){
            if(buf[i] > ‘0‘){
                buf[i] --;
                break;
            }
            else buf[i] = ‘9‘;
        }
        ans -= calc(buf);
        ans %= MOD;
        scanf("%s", buf);
        ans += calc(buf);
        ans %= MOD;
        if(ans < 0) ans += MOD;
        printf("%d\n", ans);
    }
    return 0;
}



ZOJ 3494 BCD Code (AC自己主动机 + 数位DP)