超级神奇有趣题。

AC自动机+数位DP。其实,数位DP在处理含有某些数字时特别不好处理,应该把它倒转为求不含有。这道题把数位DP+AC自动机结合起来,实在是很巧妙,把数字变为串来处理,强大!

要使用AC自动机来处理数位DP,首先就是要确定哪些状态由当前状态开始是不可以到达的,有哪些是可以到达的。这是显而易见的,因为既然是数位DP,必定涉及到数字的问题,每改变一个数字就会到达自动机上的一个状态,确定哪些状态可达或不可达是很有必要的。这就要求要构建trie图了。

其次就是DFS了,在进行DFS深搜前,要确定当前状态变更一个数字后的状态是否可达,再进行转移。

在这题,要处理前导0的问题,因为0000(十进制)里,其实只代表一个0,但可能会出现禁止状态(如二进制连续五个0违法,但四个0不违法)。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
const LL MOD=;
const int root=;
int trie[][],tot,bit[];
int next[][],fail[];
bool tag[];
char str[];
LL dp[][];
int que[],head,tail; void clr(int now){
trie[now][]=trie[now][]=-;
} void insert(){
int p=root,i=,len=strlen(str);
while(i++<len){
if(trie[p][str[i-]-'']==-){
trie[p][str[i-]-'']=++tot;
clr(tot);
}
p=trie[p][str[i-]-''];
}
tag[p]=true;
} void build_ac(){
head=tail=;
que[tail++]=root;
while(head!=tail){
int tmp=que[head++];
int p=-;
for(int i=;i<;i++){
if(trie[tmp][i]!=-){
if(tmp==root) fail[trie[tmp][i]]=root;
else{
p=fail[tmp];
while(p!=-){
if(trie[p][i]!=-){
fail[trie[tmp][i]]=trie[p][i];
break;
}
p=fail[p];
}
if(p==-) fail[trie[tmp][i]]=root;
}
if(tag[fail[trie[tmp][i]]]) tag[trie[tmp][i]]=tag[fail[trie[tmp][i]]];
que[tail++]=trie[tmp][i];
}
else{
if(tmp==root) trie[tmp][i]=root;
else{
p=fail[tmp];
while(p!=-){
if(trie[p][i]!=-){
trie[tmp][i]=trie[p][i];
break;
}
p=fail[p];
}
if(p==-) trie[tmp][i]=root;
}
}
}
}
} void interval(){
int len=strlen(str)-;
char tmp;
for(int i=len;i>=len-i;i--){
tmp=str[i];
str[i]=str[len-i];
str[len-i]=tmp;
}
} int cal_next(int p,int j){
if(tag[p]) return -;
for(int k=;k>=;k--){
p=trie[p][(j>>k)&];
if(tag[p]) return -;
}
return p;
} void Calculation(){
for(int i=;i<=tot;i++){
for(int j=;j<=;j++){
next[i][j]=cal_next(i,j);
}
}
} LL dfs(int len,int j,bool limit,bool z){
if(len==-) return 1LL;
if(!limit&&dp[len][j]!=-) return dp[len][j];
int up=limit?bit[len]:;
LL ans=;
if(z&&len>){
ans+=dfs(len-,j,limit&&up==,true);
}
else{
if(next[j][]!=-&&!tag[next[j][]])
ans+=dfs(len-,next[j][],limit&&up==,false);
}
for(int i=;i<=up;i++){
if(next[j][i]!=-&&!tag[next[j][i]]){
ans+=dfs(len-,next[j][i],limit&&i==up,false);
}
}
ans%=MOD;
if(!limit) dp[len][j]=ans;
return ans;
} LL slove(){
int len=strlen(str);
len--;
for(int i=len;i>=;i--)
bit[i]=str[i]-'';
return dfs(len,,true,true);
} int main(){
int T,n,len;
scanf("%d",&T);
while(T--){
memset(tag,false,sizeof(tag));
memset(dp,-,sizeof(dp));
memset(fail,-,sizeof(fail));
scanf("%d",&n);
tot=;
clr(root);
for(int i=;i<n;i++){
scanf("%s",str);
// cout<<str<<endl;
insert();
}
build_ac();
Calculation();
scanf("%s",str);
// cout<<str<<endl;
len=strlen(str);
interval();
// cout<<str<<endl;
for(int i=;i<len;i++){
if(str[i]=='')
str[i]='';
else {
str[i]--;
break;
}
}
if(str[len-]==''&&len!=) str[len-]='\0';
LL ans1=slove();
scanf("%s",str);
interval();
// memset(dp,-1,sizeof(dp));
LL ans2=slove();
printf("%lld\n",((ans2-ans1)%MOD+MOD)%MOD);
}
return ;
}

ZOJ 3494的更多相关文章

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

    题目链接:  http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3494 题目大意:给定一些被禁止的BCD码.问指定范围内不含有 ...

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

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

  3. zoj 3494:BCD Code

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

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

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

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

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

  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. AC自动机-算法详解

    What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. 简单的说,KMP用来在一篇文章中匹配一个模式串:但 ...

  9. 【原创】AC自动机小结

    有了KMP和Trie的基础,就可以学习神奇的AC自动机了.AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配.           AC自动机 其实 就是创建了一个状态的转移图,思想很 ...

随机推荐

  1. bzoj 2005 & 洛谷 P1447 [ Noi 2010 ] 能量采集 —— 容斥 / 莫比乌斯反演

    题目:bzoj 2005 https://www.lydsy.com/JudgeOnline/problem.php?id=2005   洛谷 P1447 https://www.luogu.org/ ...

  2. Java多线程技术-Lock/Condition

    在java1.5中Lock对象来实现同步的效果,而且使用上更方便. 使用ReentrantLock实现同步 public class MyService { private Lock lock = n ...

  3. Hadoop Hive概念学习系列之Hive里的2维坐标系统(第一步定位行键 -> 第二步定位字段)(二十三)

    HBase里的4维坐标系统(第一步定位行键   ->   第二步定位列簇  ->  第三步定位列修饰符   ->  第四步定位时间戳) HBase里的4维坐标系统(第一步定位行键   ...

  4. android平台 cocos2d-x 读取相册数据

    现已解决 方案如下: 1.使用 jni 调用 java 方法 启动相册选择框2.使用java将获取的图片保存到本地3.使用Cocos2d-x中 CCImage 读取 JAVA代码如下: //启动图片选 ...

  5. sql server 查询时间 格式化输出

    use test select * from vote insert into vote (contents) values(GETDATE()) insert into vote (contents ...

  6. mui scrollTo到指定位置,出现空白页及拉不动的问题解决

    使用方式简介 mui 列表页使用的是 mui的插件实现的上拉加载下拉刷新,但是从详情页回到列表页时 不能回到之前的位置.所以想到了使用缓存. 第一次和第二次的试验是失败的.失败后,就想用其他办法来解决 ...

  7. mount 命令总结

    配置CnetOS 7.4 本地yum源,记录下遇到的ISO镜像挂载问题,使用 blkid 命令可以查看设备的UUID.Label.文件系统类型(iso镜像文件系统类型iso9660) [root@lo ...

  8. 团体程序设计天梯赛-练习集-*L1-043. 阅览室

    L1-043. 阅览室 天梯图书阅览室请你编写一个简单的图书借阅统计程序.当读者借书时,管理员输入书号并按下S键,程序开始计时:当读者还书时,管理员输入书号并按下E键,程序结束计时.书号为不超过100 ...

  9. 团体程序设计天梯赛-练习集-L1-038. 新世界

    L1-038. 新世界 这道超级简单的题目没有任何输入. 你只需要在第一行中输出程序员钦定名言“Hello World”,并且在第二行中输出更新版的“Hello New World”就可以了. #in ...

  10. PHP共享内存

    如何使用 PHP shmop 创建和操作共享内存段,使用它们存储可供其他应用程序使用的数据. 1. 创建内存段 共享内存函数类似于文件操作函数,但无需处理一个流,您将处理一个共享内存访问 ID.第一个 ...