题意:

  将一个整数表示成4个bit的bcd码就成了一个01串,如果该串中出现了部分病毒串,则是危险的。给出n个病毒串(n<=100,长度<21),问区间[L,R]中有几个数字是不含病毒串的(结果需要取模)?(0<L<=R<=10200

思路:

  区间非常大,怎样暴力统计都是不科学的。首先确定状态,按传统,一维必定是位数,二维就是压缩的状态了,如果长度为20个bit的话,200*104万的数组是不行的。类似多模式串匹配问题,病毒串可以构建成AC自动机,那么每个点可以代表一个独立状态,而n<=100,所以最多20n个节点,是可以的。转移的话可以根据新考虑的数位是多少,然后在AC自动机上面走4步(BCD码是4bit)到达另一个状态(点),如果经过了病毒串的末尾节点,表示该数出现病毒串,就不能转移。这个可以在AC自动机创建完成后,预处理出来就行了。而对于每个询问[L,R],L仍然是需要减1的,大数减1比较简单。注意点是,AC自动机上的tag需要特殊处理,如果有病毒串"asdf"和串"sd",而碰到原串为"asdd",别忘了还有"sd"。这只需要在构建fail指针的时候处理一下。

 #include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <algorithm>
#include <vector>
#include <iostream>
#define pii pair<int,int>
#define INF 0x7f3f3f3f
#define LL long long
#define ULL unsigned long long
using namespace std;
const double PI = acos(-1.0);
const int N=;
const LL mod=; struct Trie{
static const int NN=; //节点数
static const int CC=; //孩子数
int next[NN][CC], fail[NN];
bool tag[NN];
int root, node_cnt;
int newnode(){
for(int i=; i<CC; i++) next[node_cnt][i]=-;
tag[node_cnt]=false; //刚创建时,默认非叶子
return node_cnt++;
}
void init(){
node_cnt=;
root=newnode(); //root是虚拟点
}
void insert(char s[]){
int len=strlen(s);
int now=root;
for(int i=; i<len; i++){
if(next[now][s[i]-'']==-)
next[now][s[i]-'']=newnode();
now=next[now][s[i]-''];
}
tag[now]=true; //尾节点:可能有多个相同模式串!
}
void buildAC(){
fail[root]=root; queue<int> que;
for(int i=; i<CC; i++){
if(next[root][i]==-)
next[root][i]=root;
else{
fail[next[root][i]]=root;
que.push(next[root][i]);
}
}
while(!que.empty()){
int now=que.front();que.pop();
if(tag[fail[now]]==true) tag[now]=true; //注意
for(int i=; i<CC; i++){
if( next[now][i]==-)
next[now][i]=next[fail[now]][i];
else{
fail[next[now][i]]=next[fail[now]][i];
que.push(next[now][i]);
}
}
}
}
}AC; LL f[N][N*];
int bcd[N*][], len;
char bit[N]; LL dfs(int i,int s,int sum,bool e) //s是节点编号
{
if(i==) return ;
if(!e&&~f[i][s]) return f[i][s]; LL ans=;
if(sum==) //处理前缀0
{
ans+=dfs(i-, s, , e&&bit[i]=='');
ans%=mod;
} int d= sum>? : ; //起
int u= e? bit[i]-'': ;//终
for(; d<=u; d++)
{
if(bcd[s][d]!=-)
{
ans+=dfs(i-, bcd[s][d], sum+d, e&&d==u);
ans%=mod;
}
}
if(!e&&sum) f[i][s]=ans; //没有前导零
return ans;
} LL cal()
{
reverse(bit+, bit+len+);
if(len==&&bit[len]=='') return ;
return dfs(len, , , true);
} int changeto(int s,int t)
{
if(AC.tag[s]) return -; //已经是病毒串
int now=s;
for(int i=; i>=; i--)
{
if( AC.tag[AC.next[now][(t>>i)&]]== ) return -; //病毒串
now=AC.next[now][(t>>i)&];
}
return now;
}
void pre_cal() //预处理转移
{
for(int i=; i<AC.node_cnt; i++)
for(int j=; j<; j++)
bcd[i][j]=changeto(i,j);
}
int main()
{
freopen("input.txt","r",stdin);
int t, n;cin>>t;
LL ans[];
while( t-- )
{
memset(bcd, -, sizeof(bcd));
memset(f, -, sizeof(f));
AC.init();
scanf("%d",&n);
for(int i=; i<n; i++)
{
scanf("%s",bit);
AC.insert(bit);
}
AC.buildAC(); //AC自动机
pre_cal(); //预处理转移 for(int j=; j<; j++)
{
scanf("%s", bit+);
len=strlen(bit+);
if(j==)
{
for(int i=len; i>; i--) //注意逆序
{
if( bit[i]>'' ){bit[i]--;break;}
else bit[i]='';
}
}
ans[j]=cal();
}
printf("%lld\n",(ans[]+mod-ans[])%mod);
}
return ;
}

AC代码

ZOJ 3494 BCD Code (数位DP,AC自动机)的更多相关文章

  1. ZOJ 3494 BCD Code(AC自动机 + 数位DP)题解

    题意:每位十进制数都能转化为4位二进制数,比如9是1001,127是 000100100111,现在问你,在L到R(R <= $10^{200}$)范围内,有多少数字的二进制表达式不包含模式串. ...

  2. 咕咕(数位dp+AC自动机)

    咕咕(数位dp+AC自动机) 若一个字符串的字符集合是0~m-1,那么称它为m进制字符串.给出n个m进制字符串\(s_i\),每个字符串的权值为\(v_i\).对于另一个m进制字符串\(S\),设\( ...

  3. ZOJ 3494 BCD Code(AC自动机+数位DP)

    BCD Code Time Limit: 5 Seconds      Memory Limit: 65536 KB Binary-coded decimal (BCD) is an encoding ...

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

    题目链接:BCD Code 解析:n个病毒串.问给定区间上有多少个转换成BCD码后不包括病毒串的数. 很奇妙的题目. . 经典的 AC自己主动机 + 数位DP 的题目. 首先使用AC自己主动机,得到b ...

  5. zoj 3494:BCD Code

    Description Binary-coded decimal (BCD) is an encoding for decimal numbers in which each digit is rep ...

  6. FZU 2113 BCD Code 数位dp

    数位dp,但是很奇怪的是我在虚拟oj上用GUC C++提交会wa,用Visual c++提交正确,但是加上注释后提交又莫名CE--好任性啊 0 ,0 题目思路:看代码吧 注释很详细 #include& ...

  7. 2019.02.15 codechef Favourite Numbers(二分+数位dp+ac自动机)

    传送门 题意: 给444个整数L,R,K,nL,R,K,nL,R,K,n,和nnn个数字串,L,R,K,数字串大小≤1e18,n≤65L,R,K,数字串大小\le1e18,n\le65L,R,K,数字 ...

  8. [Sdoi2014]数数[数位dp+AC自动机]

    3530: [Sdoi2014]数数 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 834  Solved: 434[Submit][Status][ ...

  9. CF 434C Tachibana Kanade's Tofu[数位dp+AC自动机]

    Solution //本代码压掉后两维 #include<cstdio> #define max(a,b) (a<b?b:a) using namespace std; inline ...

随机推荐

  1. 面试题: mysql数据库 已看1 索引和事务 没用

    mysql数据库面试总结 2017年09月04日 00:11:40 阅读数:151 结合网上大神还有自己面试经历,收集的总结Mysql面试题,方便自己准备面试: mysql一个永远都复习不完,尽量总结 ...

  2. 使用BIND安装智能DNS服务器(三)---添加view和acl配置

    智能DNS的配置主要修改named.conf文件,利用view和acl来实现. acl文件内容,这里只列出一部分,具体详细的可以参考这个网址 纯真IP库,给出了十分详细的IP地址,下载安装后,打开软件 ...

  3. Spring入门第十三课

    通过FactoryBean来配置Bean package logan.spring.study.factoryBean; public class Car { private String brand ...

  4. javascript 函数属性prototype(转)

    在JavaScript中并没有类的概念,但javascript中的确可以实现重载,多态,继承.这些实现其实方法都可以用JavaScript中的引用和变量作用域结合prototype来解释. 1.pro ...

  5. LightOJ - 1234 LightOJ - 1245 Harmonic Number(欧拉系数+调和级数)

    Harmonic Number In mathematics, the nth harmonic number is the sum of the reciprocals of the first n ...

  6. HTML前端入门归纳——控件

    本人一直在从事.net的开发,界面都是采用的WPF,近期花了一个多月进行HTML前端的学习,在这里呢进行学习总结和归纳. 本系列将主要分为4个模块: 控件 样式 布局 JavaScript 根据多年W ...

  7. Linux下查看磁盘剩余空间和文件夹大小

    1. du -sh 查看当前文件夹大小 2. du -sh * | sort -n 列出当前文件夹下的所有文件夹及其大小,并按照文件夹大小排序 du - sh *  //查看当前文件夹下所有文件的大小 ...

  8. Google Analytics & Webtrend 使用笔记

    GA和webtrend中的参数,每每遇到了都记不住.遇到一点记一点好了... Page Views(PV): 浏览次数.用户每打开一个页面,记录为1个PV:用户多次打开同一个页面,PV累计多次. Da ...

  9. 测试REST Web服务

    EST Web服务的测试计划 线程组 HTTP请求 与任何Jmeter测试一样,我们首先需要创建一个线程组以及一个HTTP请求采样器. 如果您现在运行测试,则可能会收到错误,响应代码为415,响应消息 ...

  10. 关于企业邮箱无法提醒解决办法(未安装邮件客户端可添加至网易邮箱大师/qq邮箱等)

    关于企业邮箱无法提醒解决办法: 一.使用现有的邮箱客户端,以下以网易的邮箱大师为例mail.exe 点击客户端左边的添加邮箱账号,在出现的对话框中输入账号和密码后,点击登陆按钮后,等待添加完成即可,邮 ...