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 ...
随机推荐
- Centos7更新阿里yum源
一.下载repo文件 wget http://mirrors.aliyun.com/repo/Centos-7.repo 二.备份并替换系统的repo文件 cp Centos-7.repo /etc/ ...
- C#连接Oracle数据库解决报错(需要安装Oracle客户端软件8.1.7)的问题
1.通过nuget安装 ManagedDataAccess 2.引用 using Oracle.ManagedDataAccess.Client; 注:最低framework4.0 测试连接: // ...
- python dict操作
d1 = {'one': 1, 'two': 2} d2 = {'one': 1, 'two': 2} d3 = {'one': 1, 'two': 2} print(dir(d1)) # 1.con ...
- 洛谷P1368 均分纸牌(加强版)
P1368 均分纸牌(加强版) 题目描述 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,纸牌总数必为 N 的倍数.可以在任一堆上取1张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取 ...
- Java基础--面向对象以及相关知识
一. 面向对象特征与原则 1.三大特征:封装.继承.多态. (1)封装:将客观的事物封装成抽象的类,封装代码逻辑,并通过访问控制符来控制访问的方式,从而保护程序(使用反射时,可以获取对象的私有方法和成 ...
- 11.Python初窥门径(函数名,可迭代对象,迭代器)
Python(函数名,可迭代对象,迭代器) 一.默认参数的坑 # 比较特殊,正常来说临时空间执行结束后应该删除,但在这里不是. def func(a,l=[]): l.append(a) return ...
- glassfish 自定义 jaas realm
https://www.oschina.net/translate/custom-jaas-realm-for-glassfish-3
- C# 流
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- easyui---datalist相关知识
datalist 笔记: class:class="easyui-datalist" //对应标准元素:ul 表格线:lines="true" 远程数据绑定: ...
- jdbc查询
import java.util.ArrayList; import java.util.List; import org.springframework.jdbc.core.BeanProperty ...