zoukankan      html  css  js  c++  java
  • 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
    ", ans);
        }
        return 0;
    }
    



  • 相关阅读:
    Android腾讯微薄客户端开发七:图片加圆角以及时间处理工具类
    【Android】SDK NoteEditor源码研究(一、组件重载)
    【Android】Animation动画(一)
    【JAVA】将PDF转化成图片
    【Android】组件ViewFlipper的滑稽
    【Android】Paint的效果研究
    【DB】数据库的范式
    【Android】动态弹出组件(Layout)
    【Android】Animation动画(二)
    【Android】Scroller分析
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/6907649.html
Copyright © 2011-2022 走看看