ZOJ 3494
超级神奇有趣题。
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的更多相关文章
- ZOJ 3494 (AC自动机+高精度数位DP)
题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3494 题目大意:给定一些被禁止的BCD码.问指定范围内不含有 ...
- ZOJ 3494 BCD Code(AC自动机+数位DP)
BCD Code Time Limit: 5 Seconds Memory Limit: 65536 KB Binary-coded decimal (BCD) is an encoding ...
- zoj 3494:BCD Code
Description Binary-coded decimal (BCD) is an encoding for decimal numbers in which each digit is rep ...
- ZOJ 3494 BCD Code (数位DP,AC自动机)
题意: 将一个整数表示成4个bit的bcd码就成了一个01串,如果该串中出现了部分病毒串,则是危险的.给出n个病毒串(n<=100,长度<21),问区间[L,R]中有几个数字是不含病毒串的 ...
- ZOJ 3494 BCD Code (AC自己主动机 + 数位DP)
题目链接:BCD Code 解析:n个病毒串.问给定区间上有多少个转换成BCD码后不包括病毒串的数. 很奇妙的题目. . 经典的 AC自己主动机 + 数位DP 的题目. 首先使用AC自己主动机,得到b ...
- BCD Code ZOJ - 3494 AC自动机+数位DP
题意: 问A到B之间的所有整数,转换成BCD Code后, 有多少个不包含属于给定病毒串集合的子串,A,B <=10^200,病毒串总长度<= 2000. BCD码这个在数字电路课上讲了, ...
- ZOJ 3494 BCD Code(AC自动机 + 数位DP)题解
题意:每位十进制数都能转化为4位二进制数,比如9是1001,127是 000100100111,现在问你,在L到R(R <= $10^{200}$)范围内,有多少数字的二进制表达式不包含模式串. ...
- AC自动机-算法详解
What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. 简单的说,KMP用来在一篇文章中匹配一个模式串:但 ...
- 【原创】AC自动机小结
有了KMP和Trie的基础,就可以学习神奇的AC自动机了.AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配. AC自动机 其实 就是创建了一个状态的转移图,思想很 ...
随机推荐
- iOS版本、iPhone版本、Xcode版本比对
iOS版本 iPhone版本 Xcode版本 其他 2003年 Xcode1.0 2005年4月29日 Xcode2.0 2007年1月9日 iPhone OS(iOS1): 虚拟键盘.谷歌地图 第一 ...
- 昂贵的聘礼(Dijkstra)
http://poj.org/problem?id=1062 每个物品看成一个节点,酋长的允诺也看作一个物品, 如果一个物品加上金币可以交换另一个物品,则这两个节点之间有边,权值为金币数,求第一个节点 ...
- C#WebForm里面aspx,ajax请求后台。。。
虽然WebForm里面有那些基本控件,后台CS里面也有许许多多的控件的方法.但是不见得有些标签不需要进行后台的访问,下面介绍一下三种aspx中访问后台的方式.. 第一种:WebMethod (静态方法 ...
- 在窗体中把DataGridView中的数据导出Excel
//DataGridView导出Excel private void bt_Excl_Click(object sender, EventArgs e) { SaveFileDialog saveFi ...
- 省市区县的sql语句——区县
DROP TABLE IF EXISTS `area`; CREATE TABLE `area` ( `id` int(11) NOT NULL AUTO_INCREMENT, `code` va ...
- Deutsch lernen (01)
Was macht Martin? - Um 8.00 Uhr steht martin auf. aufstehen - aufstand - ist aufgestanden 起床 Um 6 Uh ...
- 转:Fiddler抓包工具总结
http://www.cnblogs.com/yyhh/p/5140852.html#l02
- fatal error C1083: 无法打开包括文件:“stdio.h
现象: vs2012一直fatal error C1083: 无法打开包括文件:"stdio.h" 不知道配置太多,动到了什么地方,出现了这个问题: 在: 解决方案--调试源文件 ...
- PCL:描述三维离散点的ROPS特征(Code)
前言: 三维点云为三维欧式空间点的集合.对点云的形状描述若使用局部特征,则可分为两种:固定世界坐标系的局部描述和寻找局部主方向的局部描述,ROPS特征为寻找局部主方向的特征描述. 1.寻找主方向(对X ...
- 11.02 跳过表中n行
select x.enamefrom (select a.ename,(select count(*)from emp bwhere b.ename <=a.ename) as rnfrom e ...