Binary-coded decimal (BCD) is an encoding for decimal numbers in which each digit is represented by its own binary sequence. To encode a decimal number using the common BCD encoding,
each decimal digit is stored in a 4-bit nibble:

Decimal:    0     1     2     3     4     5     6     7     8     9
BCD: 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001

Thus, the BCD encoding for the number 127 would be:

 0001 0010 0111

We are going to transfer all the integers from A to B, both inclusive, with BCD codes. But we find that some continuous bits, named forbidden code, may lead to errors.
If the encoding of some integer contains these forbidden codes, the integer can not be transferred correctly. Now we need your help to calculate how many integers can be transferred correctly.

Input

There are multiple test cases. The first line of input is an integer T ≈ 100 indicating the number of test cases.

The first line of each test case contains one integer N, the number of forbidden codes ( 0 ≤ N ≤ 100). Then N lines follow, each of which contains a 0-1 string
whose length is no more than 20. The next line contains two positive integers A and B. Neither A or B contains leading zeros and 0 < A ≤ B < 10200.

Output

For each test case, output the number of integers between A and B whose codes do not contain any of the N forbidden codes in their BCD codes. For the result
may be very large, you just need to output it mod 1000000009.

Sample Input

3
1
00
1 10
1
00
1 100
1
1111
1 100

Sample Output

3
9

98

题意:给出一些模式串,给出一个范围[A,B],求出区间内有多少个数,写成BCD之后,不包含模式串。

思路:先用AC自动机存下不符合的节点,然后预处理出bcd[i][j]表示ac自动机节点i走j这个数后的节点编号或者-1,然后用dp[i][j]表示前i位,当前ac节点为j的方案数。

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef long double ldb;
#define inf 99999999
#define pi acos(-1.0)
#define maxn 300050
#define maxnode 2050
#define MOD 1000000009
int bcd[maxnode][11]; //bcd[i][j]表示ac自动机状态i走j步后的状态 struct trie{
int sz,root,val[maxnode],next[maxnode][2],fail[maxnode];
int q[11111];
void init(){
int i;
sz=root=0;
val[0]=0;
for(i=0;i<2;i++){
next[root][i]=-1;
}
}
void charu(char *s){
int i,j,u=0;
int len=strlen(s);
for(i=0;i<len;i++){
int c=s[i]-'0';
if(next[u][c]==-1){
sz++;
val[sz]=0;
next[u][c]=sz;
u=next[u][c];
for(j=0;j<2;j++){
next[u][j]=-1;
}
}
else{
u=next[u][c];
}
}
val[u]=1;
} void build(){
int i,j;
int front,rear;
front=1;rear=0;
for(i=0;i<2;i++){
if(next[root][i]==-1 ){
next[root][i]=root;
}
else{
fail[next[root][i] ]=root;
rear++;
q[rear]=next[root][i];
}
}
while(front<=rear){
int x=q[front];
if(val[fail[x]]) //!!!!!
val[x]=1;
front++;
for(i=0;i<2;i++){
if(next[x][i]==-1){
next[x][i]=next[fail[x] ][i];
}
else{
fail[next[x][i] ]=next[fail[x] ][i];
rear++;
q[rear]=next[x][i];
} }
}
}
}ac; int change(int jiedian,int num)
{
int i,j,len=0;
int shu[10];
while(num){
shu[++len]=num%2;
num/=2;
}
while(len<4)shu[++len]=0;
for(i=4;i>=1;i--){
if(ac.val[ac.next[jiedian][shu[i] ] ]==1 )return -1;
else jiedian=ac.next[jiedian][shu[i] ];
}
return jiedian;
} void pre_init()
{
int i,j;
for(i=0;i<=ac.sz;i++){
for(j=0;j<=9;j++){
bcd[i][j]=change(i,j);
}
}
} int wei[300];
ll dp[300][maxnode]; ll dfs(int pos,int jiedian,int lim,int zero)
{
int i,j;
if(pos==-1)return 1;
if(lim==0 && zero==0 && dp[pos][jiedian]!=-1){ //这里和下面同理,也不要省略zero==0
return dp[pos][jiedian];
}
int ed=lim?wei[pos]:9;
ll ans=0;
for(i=0;i<=ed;i++){
if(i==0){
if(zero){
ans+=dfs(pos-1,jiedian,0,1);
ans%=MOD;
}
else{
if(bcd[jiedian][0]!=-1){
ans+=dfs(pos-1,bcd[jiedian][0],lim&&i==ed,0);
ans%=MOD;
}
}
continue;
}
if(bcd[jiedian][i]!=-1){
ans+=dfs(pos-1,bcd[jiedian][i],lim&&i==ed,0);
ans%=MOD;
}
}
if(lim==0 && zero==0 ){ //这里要注意,不能写成if(lim==0)dp[pos][jiedian]=ans;因为zero不为0的话,即最高位还没有确定,那么可能后面几位都可以跳过去,
dp[pos][jiedian]=ans; //即可以把0跳过,但是对于最高位确定的情况下,后面不管加什么数都不能跳过去,即使是0也要在ac自动机上走0这个数.
}
return ans;
} ll cal(char *s)
{
int i,j,len;
len=strlen(s);
for(i=0;i<len;i++){
wei[i]=s[len-1-i]-'0';
}
return dfs(len-1,0,1,1);
} char s1[300],s2[300],s[30];
int main()
{
int n,m,i,j,T,len1,len2;
scanf("%d",&T);
while(T--)
{
ac.init();
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%s",s);
ac.charu(s);
}
ac.build();
pre_init();
scanf("%s",s1);
len1=strlen(s1);
reverse(s1,s1+len1);
for(i=0;i<len1;i++){ //这里算的是(l,r],所以先要把s1的数减去1
if(s1[i]-'0'>0){
s1[i]--;break;
}
else{
s1[i]='9';
}
}
memset(dp,-1,sizeof(dp));
ll ans=0;
if(s1[len1-1]=='0')len1-=1;
s1[len1]='\0';
reverse(s1,s1+len1);
ans-=cal(s1);
ans%=MOD;
scanf("%s",s2);
ans+=cal(s2);
ans%=MOD;
if(ans<0){
ans=(ans+MOD)%MOD;
}
printf("%lld\n",ans);
}
return 0;
}

zoj3494 BCD Code(AC自动机+数位dp)的更多相关文章

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

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

  2. zoj3494BCD Code(ac自动机+数位dp)

    l链接 这题想了好一会呢..刚开始想错了,以为用自动机预处理出k长度可以包含的合法的数的个数,然后再数位dp一下就行了,写到一半发现不对,还要处理当前走的时候是不是为合法的,这一点无法移到trie树上 ...

  3. 【HDU3530】 [Sdoi2014]数数 (AC自动机+数位DP)

    3530: [Sdoi2014]数数 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 682  Solved: 364 Description 我们称一 ...

  4. 【bzoj3530】[Sdoi2014]数数 AC自动机+数位dp

    题目描述 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串.例如当S=(22,333,0233)时,233是幸运数,2333.20233.3223不是幸运 ...

  5. BZOJ 3530 [SDOI2014]数数 (Trie图/AC自动机+数位DP)

    题目大意:略 裸的AC自动机+数位DP吧... 定义f[i][x][0/1]表示已经匹配到了第i位,当前位置是x,0表示没到上限,1到上限,此时数是数量 然而会出现虚拟前导零,即前几位没有数字的情况, ...

  6. BCD Code ZOJ - 3494 AC自动机+数位DP

    题意: 问A到B之间的所有整数,转换成BCD Code后, 有多少个不包含属于给定病毒串集合的子串,A,B <=10^200,病毒串总长度<= 2000. BCD码这个在数字电路课上讲了, ...

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

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

  8. BZOJ3530:[SDOI2014]数数(AC自动机,数位DP)

    Description 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串.例如当S=(22,333,0233)时,233是幸运数,2333.20233.3 ...

  9. 【JZOJ3624】【SDOI2014】数数(count) AC自动机+数位dp

    题面 100 容易想到使用AC自动机来处理禁忌子串的问题: 然后在自动机上数位dp,具体是: \(f_{i,j,0/1}\)表示填了\(i\)位,当前在自动机的第\(j\)个结点上,\(0\)表示当前 ...

随机推荐

  1. stat filename

    查看文件的mtime,atime,ctime 3个时间

  2. 【Python】简单的脚本,轻松批量修改文件名称

    使用python脚本,批量修改文件夹名称 先创建一些没用的案例文件 import os #创建新文件夹 dir = os.makedirs('D:\\SomeThing\\testfile') #将文 ...

  3. 利用Numpy求解投资内部收益率IRR

    一. 内部收益率和净现值 内部收益率(Internal Rate of Return, IRR)其实要和净现值(Net Present Value, NPV)结合起来讲.净现值指的是某个投资项目给公司 ...

  4. ctfhub技能树—RCE—综合过滤练习

    打开靶机 查看页面信息 查看源码可以发现这一次过滤了很多东西,查看当前目录信息 查询到%0a为换行符,可以利用这个url编码进行命令注入,开始尝试 http://challenge-2a4584dab ...

  5. 实现简易版德州扑克|学习麻瓜编程以项目为导向入门前端 HTML+CSS+JS

    实现简易版德州扑克 1.先上达到网页效果图(简易版德州扑克) 网页分为发牌区和牌池,上面为发牌区,下面是牌池区 2. 代码实现 2.1 HTML和JS代码 ` <link rel="s ...

  6. 学习Java第一天

    public 保证类名和文件名一致 关键字字母全小写,编辑器中有颜色标记 null空常量不能打印 变量就是内存中的存储空间 计算机中最小的存储单元时字节(byte) //1字节(B) = 8位(bit ...

  7. tf

    第2章 Tensorflow keras实战 2-0 写在课程之前 课程代码的Tensorflow版本 大部分代码是tensorflow2.0的 课程以tf.kerasAPI为主,因而部分代码可以在t ...

  8. 001.IT运维面试问题-Linux基础

    Linux基础 简述Linux主流的发行版? Redhat.CentOS.Fedora.SuSE.Debian.Ubuntu.FreeBSD等. 简述Linux启动过程? ⑴开机BIOS自检,加载硬盘 ...

  9. Architecture and design 洋葱 中间件 装饰器

    Go kit - Frequently asked questions https://gokit.io/faq/ Architecture and design Introduction - Und ...

  10. oracle创建表并加索引

    一个语句创建Oracle所有表的序列 -- 动态创建序列 2 declare 3 cursor c_job is 4 select TABLE_NAME from user_tables; 5 6 c ...