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自动机,那么每个点可以代表一个独立状态,而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自动机)的更多相关文章
- ZOJ 3494 BCD Code(AC自动机 + 数位DP)题解
题意:每位十进制数都能转化为4位二进制数,比如9是1001,127是 000100100111,现在问你,在L到R(R <= $10^{200}$)范围内,有多少数字的二进制表达式不包含模式串. ...
- 咕咕(数位dp+AC自动机)
咕咕(数位dp+AC自动机) 若一个字符串的字符集合是0~m-1,那么称它为m进制字符串.给出n个m进制字符串\(s_i\),每个字符串的权值为\(v_i\).对于另一个m进制字符串\(S\),设\( ...
- 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 (AC自己主动机 + 数位DP)
题目链接:BCD Code 解析:n个病毒串.问给定区间上有多少个转换成BCD码后不包括病毒串的数. 很奇妙的题目. . 经典的 AC自己主动机 + 数位DP 的题目. 首先使用AC自己主动机,得到b ...
- zoj 3494:BCD Code
Description Binary-coded decimal (BCD) is an encoding for decimal numbers in which each digit is rep ...
- FZU 2113 BCD Code 数位dp
数位dp,但是很奇怪的是我在虚拟oj上用GUC C++提交会wa,用Visual c++提交正确,但是加上注释后提交又莫名CE--好任性啊 0 ,0 题目思路:看代码吧 注释很详细 #include& ...
- 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,数字 ...
- [Sdoi2014]数数[数位dp+AC自动机]
3530: [Sdoi2014]数数 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 834 Solved: 434[Submit][Status][ ...
- CF 434C Tachibana Kanade's Tofu[数位dp+AC自动机]
Solution //本代码压掉后两维 #include<cstdio> #define max(a,b) (a<b?b:a) using namespace std; inline ...
随机推荐
- angular学习的一些Mark
http://www.cnblogs.com/xianrongbin/p/4104596.html http://angular-ui.github.io/
- <c和指针>学习笔记3之函数和数组
1 函数声明 (1)原型 告诉编译器函数的参数数量和每个参数的类型以及返回值的类型.编译器通过检查原型之后,就可以检查这个函数得调用,从而来确保参数正确,返回值无误. 通用技巧,将原型写在一个头文件当 ...
- PHP注释-----PHPDOC
用过IDE或看过其他源码的小伙伴们应该都见过类似下面这样的注释 /** * 递归获取所有游戏分类 * @param int $id * @return array */ 看得多了就大概知道了一些规 ...
- IT兄弟连 Java语法教程 Java开发环境 JVM、JRE、JDK
要想开发Java程序,就需要知道什么是JVM.JRE以及JDK.JVM是运行Java程序的核心,JRE是支持Java程序运行的环境,而JDK是Java开发的核心,下面我们分别具体介绍它们以及它们之间的 ...
- CF1141F Same Sum Blocks(easy/hard)
传送门easy 传送门hard 切水题的感觉真好 看到数据范围这么小,所以暴力枚举所有的可能,然后用map+vector存下每种值的区间,然后贪心去选 代码: #include<cstdio&g ...
- PostgreSQL - invalid input syntax for type timestamp with time zone
问题 在执行以下sql时报错: select COALESCE(null,null,now(),''); 报错如下: SQL Error [22007]: ERROR: invalid input s ...
- C语言中 malloc函数用法
一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...
- AtCoder Regular Contest 082 ABCD
A #include<bits/stdc++.h> using namespace std; ]; int n,m; int main(){ cin>>n>>m; ...
- Netty(3)Time protocol
本节介绍TIME协议.该协议与前边的discard协议和echo协议的不同点在于:1.服务端主动发送消息给到客户端,所以需要channelActive()方法.2.发送的消息是4个字节的int3.不接 ...
- Linux .Net Core
Linux .Net Core自宿主应用程序瘦身记 一,.NET Core 自宿主应用程序个头有点大 发布.NET Core应用程序有两个方式,一种是“便携式”,一种是“自宿主式”.便携式发布时,目标 ...