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 ...
随机推荐
- iview组件select之默认展示label,并传空value做方法入参
要求: 默认查询操作日期在当日的数据:(打开页面时默认选中时间.全部) 后台约定:选定“全部”这个条件,传的值是空"" 综上:使用select选择框的v-model绑定数据,使用: ...
- [poj]1050 To the Max dp
Description Given a two-dimensional array of positive and negative integers, a sub-rectangle is any ...
- 使用ffmpeg编码时,如何设置恒定码率,并控制好关键帧I帧间隔
1. 大家在使用ffmpeg进行视频编码时,使用-b命令,想控制比特率,却发现结果并没有如我们设置所愿,通过码流分析器观察视频码流,码率的波动还是很大的,ffmpeg控制的并不好,这时候,我们可以通过 ...
- 一些unity资源
雨凇解包 http://www.xuanyusong.com/archives/3618 http://www.cnblogs.com/lixiang-share/p/5840444.html u3d ...
- 洛谷P1313 计算系数
P1313 计算系数 题目描述 给定一个多项式(by+ax)^k,请求出多项式展开后x^n*y^m 项的系数. 输入输出格式 输入格式: 输入文件名为factor.in. 共一行,包含5 个整数,分别 ...
- [Xcode 实际操作]五、使用表格-(8)自定义UITableView单元格Accessory样式(附件图标)
目录:[Swift]Xcode实际操作 本文将演示如何自定义单元格的附件图标. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit //首先添 ...
- appium服务——封装生成可用端口
一.判断端口是否可用 1.在windows中判断端口是否可用,使用dos命令"netstat -ano| findstr 8080".运行结果有如下两种 如果没有被占用,就是结果为 ...
- NOIp知识集合 By cellur925
基本算法 快速幂 ll ksm(ll a,ll b) { ll ans=; while(b) { ) ans=ans*a%p; b>>=; a=a*a%p; } return ans; } ...
- JS高级学习历程-4
4 执行环境可以访问什么变量 具体可以访问变量类型:局部变量.参数.函数.外部环境变量 优先级:局部变量 > 函数 > 参数 > 外部环境变量 <!DOCTYPE html&g ...
- excel 公式2列合并
=A2&"="&C2 ="UPDATE comm_department SET parent_id='"&D2&"' ...