ZOJ 3494 (AC自动机+高精度数位DP)

题目链接:  http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3494

题目大意:给定一些被禁止的BCD码。问指定范围内不含有任何这些禁止的BCD码的数的个数。

解题思路

AC自动机部分:

首先insert这些被禁止的BCD码。

然后打一下自动机前后状态的转移的表,用BCD[i][j]表示自动机状态i时,下一个数字是j的自动机的下一个状态。

一开始我考虑最先dfs的位在自动机的位置,后来发现SB了。AC自动机有一个root状态,也就是自动机位置为0的状态,使用这个0就行了。

即f函数中dfs(len,0,true,true),每次由root状态出发,无须再考虑其它的。

数位DP部分:

本题的范围是高精度范围,所以需要特有的高精度写法。

麻烦的在于f(l-1),要为高精度手艹一个-1,有种偷懒的写法,不过会导致出现前导0。

所以在传统的dfs中需要增加一个前导0的判断。

方法是:追加一个bool z,

在原有的0~9基础上,单独考虑0,

if(z) 则单独dfs前导0

否则dfs正常的0,1~9照常dfs。当然还需要判断当前状态s的下一个状态BCD[s][i]是否符合要求。

然后最后就是注意一下负数mod。

#include "cstdio"
#include "cstring"
#include "queue"
#include "iostream"
using namespace std;
#define maxp 25*105
#define mod 1000000009
struct Trie
{
    Trie *next[2],*fail;
    int cnt;
}pool[maxp],*root,*sz;
int BCD[maxp][10],digit[205],ccnt;
long long dp[205][maxp];
Trie *newnode()
{
    Trie *ret=sz++;
    memset(ret->next,0,sizeof(ret->next));
    ret->fail=0;
    ret->cnt=0;
    return ret;
}
void init()
{
    sz=pool;
    root=newnode();
}
void Insert(string str)
{
    Trie *pos=root;
    for(int i=0;i<str.size();i++)
    {
        int c=str[i]-‘0‘;
        if(!pos->next[c]) pos->next[c]=newnode();
        pos=pos->next[c];
    }
    pos->cnt++;
}
void getfail()
{
    queue<Trie *> Q;
    for(int c=0;c<2;c++)
    {
        if(root->next[c])
        {
            root->next[c]->fail=root;
            Q.push(root->next[c]);
        }
        else root->next[c]=root;
    }
    while(!Q.empty())
    {
        Trie *x=Q.front();Q.pop();
        for(int c=0;c<2;c++)
        {
            if(x->next[c])
            {
                x->next[c]->fail=x->fail->next[c];
                x->next[c]->cnt+=x->fail->next[c]->cnt;
                Q.push(x->next[c]);
            }
            else x->next[c]=x->fail->next[c];
        }
    }
}
int judge(int status,int num)
{
    Trie *pos=pool+status;
    if(pos->cnt) return -1;
    for(int i=3;i>=0;i--)
    {
        if(pos->next[(num>>i)&1]->cnt) return -1;
        else pos=pos->next[(num>>i)&1];
    }
    return pos-pool;
}
void getbcd()
{
    for(int i=0;i<ccnt;i++)
        for(int j=0;j<10;j++)
            BCD[i][j]=judge(i,j);
}
int dfs(int len,int s,bool fp,bool z)
{
    if(!len) return 1;
    if(!fp&&dp[len][s]!=-1) return dp[len][s];
    long long ret=0;
    int fpmax=fp?digit[len]:9;
    if(z)
    {
        ret+=dfs(len-1,s,fp&&digit[len]==0,true);
        ret%=mod;
    }
    else
    {
        if(BCD[s][0]!=-1) ret+=dfs(len-1,BCD[s][0],fp&&digit[len]==0,false);
        ret%=mod;
    }
    for(int i=1;i<=fpmax;i++)
    {
        if(BCD[s][i]!=-1) ret+=dfs(len-1,BCD[s][i],fp&&i==fpmax,false);
        ret%=mod;
    }
    if(!fp&&!z) dp[len][s]=ret;
    return ret;
}
int f(string str)
{
    int len=0;
    for(int i=str.size()-1;i>=0;i--)
        digit[++len]=str[i]-‘0‘;
    return dfs(len,0,true,true);
}
int main()
{
    //freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);
    int T,n;
    string tt;
    cin>>T;
    while(T--)
    {
        init();
        memset(dp,-1,sizeof(dp));
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>tt;
            Insert(tt);
        }
        getfail();
        ccnt=sz-pool;
        getbcd();
        cin>>tt;
        for(int i=tt.size()-1;i>=0;i--)
        {
            if(tt[i]>‘0‘) {tt[i]--;break;}
            else {tt[i]=‘9‘;}
        }
        long long ans=0;
        ans-=f(tt);
        ans%=mod;
        cin>>tt;
        ans+=f(tt);
        ans=(ans%mod+mod)%mod;
        printf("%lld\n",ans);
    }
}
2842327 neopenx ZOJ 3494 Accepted 4656 KB 210 ms C++ (g++ 4.4.5) 2976 B 2014-10-13 17:06:35
时间: 2024-10-07 12:33:57

ZOJ 3494 (AC自动机+高精度数位DP)的相关文章

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自动机,那么每个点可以代表一个独立

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>

poj 1699 Best Sequence(AC自动机+状压DP)

题目链接:poj 1699 Best Sequence 题目大意:给定N个DNA序列,问说最少多长的字符串包含所有序列. 解题思路:AC自动机+状压DP,先对字符串构造AC自动机,然后在dp[s][i]表示匹配了s,移动到节点i时候的最短步数. #include <cstdio> #include <cstring> #include <queue> #include <vector> #include <iostream> #include &

hdu 2825 aC自动机+状压dp

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

ZOJ 3430 AC自动机

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4114 Nobita did use an outstanding anti-virus software, however, for some strange reason, this software did not check email attachments. Now Nobita decide to detect viruses in emails by himse

【HDU3341】 Lost&#39;s revenge (AC自动机+状压DP)

Lost's revenge Time Limit: 5000MS Memory Limit: 65535KB 64bit IO Format: %I64d & %I64u Description Lost and AekdyCoin are friends. They always play "number game"(A boring game based on number theory) together. We all know that AekdyCoin is t

HDU 2825 Wireless Password (AC自动机 + 状态压缩DP)

题目链接:Wireless Password 解析:给 m 个单词构成的集合,统计所有长度为 n 的串中,包含至少 k 个单词的方案数. AC自动机 + 状态压缩DP. DP[i][j][k]:长度为i的字符串匹配到状态j且包含k个magic word的可能字符串个数. AC代码: #include <algorithm> #include <iostream> #include <cstdio> #include <queue> #include <

hdu 4057 AC自动机+状态压缩dp

http://acm.hdu.edu.cn/showproblem.php?pid=4057 Problem Description Dr. X is a biologist, who likes rabbits very much and can do everything for them. 2012 is coming, and Dr. X wants to take some rabbits to Noah's Ark, or there are no rabbits any more.

HDU 3341 Lost&#39;s revenge AC自动机+ 状态压缩DP

题意:这个题目和HDU2457有点类似,都是AC自动机上的状态dp,题意就是给你只含有'A','T','C','G',四个字符的子串和文本串,问你文本串如何排列才可以使得文本串中包含有更多的模式串 解题思路:我们知道了 有 num[0] 个 'A', num[1] 个 ‘T’, num[2] 个 ‘C’,num[3] 个‘G’, 我们的可以知道暴力的思路就是把所有的文本串都枚举出来然后一一匹配.我们膜拜了一下春哥以后,就可以有以下思路:  把一个串的信息压缩一下,把具有同样个数字符的串看成是同一