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;
}
时间: 2024-10-15 20:32:36

ZOJ 3494 BCD Code (AC自己主动机 + 数位DP)的相关文章

zoj 3494 BCD Code(AC自动机+数位dp)

题目链接:zoj 3494 BCD Code 题目大意:给定n个2进制串,然后有一个区间l,r,问说l,r之间有多少个数转换成BCD二进制后不包含上面的2进制串. 解题思路:AC自动机+数位dp.先对禁止串建立AC自动机,所有的单词节点即为禁止通行的节点.接着进行数位dp, 用solve(r) - solve(l-1), 这里的l需要用到大数减法.dp[i][j]表示第i为移动到节点j的可行方案数,每次枚举下一位数字,因 为是BCD二进制,所以每位数要一次性移动4个字符,中途有经过禁止点都是不行

hdu 2825 Wireless Password(ac自己主动机&amp;amp;dp)

Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4022    Accepted Submission(s): 1196 Problem Description Liyuan lives in a old apartment. One day, he suddenly found that there

POJ 3691 &amp;amp; HDU 2457 DNA repair (AC自己主动机,DP)

http://poj.org/problem?id=3691 http://acm.hdu.edu.cn/showproblem.php?pid=2457 DNA repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5690   Accepted: 2669 Description Biologists finally invent techniques of repairing DNA that contain

POJ 1625 Censored! (AC自己主动机 + 高精度 + DP)

题目链接:Censored! 解析:AC自己主动机 + 高精度 + 简单DP. 字符有可能会超过128.用map映射一下就可以. 中间的数太大.得上高精度. 用矩阵高速幂会超时,简单的DP就能解决时间的问题. AC代码: #include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> #include <queue> #include <map&

ZOJ 3494 BCD Code (数位DP,AC自动机)

题意: 将一个整数表示成4个bit的bcd码就成了一个01串,如果该串中出现了部分病毒串,则是危险的.给出n个病毒串(n<=100,长度<21),问区间[L,R]中有几个数字是不含病毒串的(结果需要取模)?(0<L<=R<=10200) 思路: 区间非常大,怎样暴力统计都是不科学的.首先确定状态,按传统,一维必定是位数,二维就是压缩的状态了,如果长度为20个bit的话,200*104万的数组是不行的.类似多模式串匹配问题,病毒串可以构建成AC自动机,那么每个点可以代表一个独立

zoj 3430 Detect the Virus(AC自己主动机)

Detect the Virus Time Limit: 2 Seconds      Memory Limit: 65536 KB One day, Nobita found that his computer is extremely slow. After several hours' work, he finally found that it was a virus that made his poor computer slow and the virus was activated

ZOJ - 3228 Searching the String (AC自己主动机)

Description Little jay really hates to deal with string. But moondy likes it very much, and she's so mischievous that she often gives jay some dull problems related to string. And one day, moondy gave jay another problem, poor jay finally broke out a

ZOJ 3228 Searching the String (AC自己主动机)

题目链接:Searching the String 解析:给一个长串.给n个不同种类的短串.问分别在能重叠下或者不能重叠下短串在长串中出现的次数. 能重叠的已经是最简单的AC自己主动机模板题了. 不能重叠的记录一下每一个匹配的串的起始位置保证不重叠就可以. AC代码: #include <bits/stdc++.h> using namespace std; struct Trie{ int next[600010][26], fail[600010], deep[600010]; int r

字符串算法之 AC自己主动机

近期一直在学习字符串之类的算法,感觉BF算法,尽管非常easy理解,可是easy超时,全部就想学习其它的一些字符串算法来提高一下,近期学习了一下AC自己主动机.尽管感觉有所收获,可是还是有些朦胧的感觉,在此总结一下,希望大家不吝赐教. 一.AC自己主动机的原理: Aho-Corasick automaton.该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之中的一个. 一个常见的样例就是给出N个单词,在给出一段包括m个字符的文章,让你找出有多少个单词在这文章中出现过,.要搞懂AC自己主动