ZOJ 3494 BCD Code(AC自动机 + 数位DP)题解
题意:每位十进制数都能转化为4位二进制数,比如9是1001,127是 000100100111,现在问你,在L到R(R <= $10^{200}$)范围内,有多少数字的二进制表达式不包含模式串。
思路:显然这是一道很明显的数位DP + AC自动机的题目。但是你要是直接把数字转化为二进制,然后在Trie树上数位DP你会遇到一个问题,以为转化为二进制后,前导零变成了四位000,那么你在DP的时候还要考虑前4位是不是都是000那样就要重新跑Trie树,显然这样是很菜(不会)的。那么肯定是想办法要变成十进制跑Trie树。
那我们就预处理出一个bcd[i][j]表示在Trie树上i节点走向数字j可不可行,这样就行了。
代码:
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<string>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2000 + 5;
const int M = 50 + 5;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
const int MOD = 1000000009;
int n, m;
int bit[205], pos;
ll dp[500][maxn];
int bcd[maxn][10];
struct Aho{
struct state{
int next[10];
int fail, cnt;
}node[maxn];
int size;
queue<int> q; void init(){
size = 0;
newtrie();
while(!q.empty()) q.pop();
} int newtrie(){
memset(node[size].next, 0, sizeof(node[size].next));
node[size].cnt = node[size].fail = 0;
return size++;
} void insert(char *s){
int len = strlen(s);
int now = 0;
for(int i = 0; i < len; i++){
int c = s[i] - '0';
if(node[now].next[c] == 0){
node[now].next[c] = newtrie();
}
now = node[now].next[c];
}
node[now].cnt = 1; } void build(){
node[0].fail = -1;
q.push(0); while(!q.empty()){
int u = q.front();
q.pop();
if(node[node[u].fail].cnt && u) node[u].cnt |= node[node[u].fail].cnt;
for(int i = 0; i < 10; i++){
if(!node[u].next[i]){
if(u == 0)
node[u].next[i] = 0;
else
node[u].next[i] = node[node[u].fail].next[i];
}
else{
if(u == 0) node[node[u].next[i]].fail = 0;
else{
int v = node[u].fail;
while(v != -1){
if(node[v].next[i]){
node[node[u].next[i]].fail = node[v].next[i];
break;
}
v = node[v].fail;
}
if(v == -1) node[node[u].next[i]].fail = 0;
}
q.push(node[u].next[i]);
}
}
}
} ll dfs(int pos, int st, bool Max, bool lead){
if(pos == -1) return 1;
if(!Max && !lead && dp[pos][st] != -1) return dp[pos][st];
int top = Max? bit[pos] : 9;
ll ans = 0;
for(int i = 0; i <= top; i++){
if(lead && i == 0 && pos != 0){
ans = (ans + dfs(pos - 1, 0, Max && i == top, lead && i == 0)) % MOD;
continue;
}
if(bcd[st][i] == -1) continue;
ans = (ans + dfs(pos - 1, bcd[st][i], Max && i == top, lead && i == 0)) % MOD;
}
if(!Max && !lead) dp[pos][st] = ans;
return ans;
} ll solve(char *s){
pos = 0;
int len = strlen(s);
for(int i = len - 1; i >= 0; i--){
bit[pos++] = s[i] - '0';
}
return dfs(pos - 1, 0, true, true);
} char num[10][5] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001"};
void init_bcd(){
memset(bcd, 0, sizeof(bcd));
for(int i = 0; i < size; i++){
for(int j = 0; j < 10; j++){
int v = i;
for(int k = 0; k < 4; k++){
v = node[v].next[num[j][k] - '0'];
if(node[v].cnt){
bcd[i][j] = -1;
break;
}
}
if(bcd[i][j] != -1) bcd[i][j] = v;
}
}
} }ac; char s1[205], s2[205];
int main(){
int T;
scanf("%d", &T);
while(T--){
memset(dp, -1, sizeof(dp));
scanf("%d", &n);
ac.init();
for(int i = 0; i < n; i++){
scanf("%s", s1);
ac.insert(s1);
}
ac.build();
ac.init_bcd(); scanf("%s%s", s1, s2);
int lens1 = strlen(s1);
int pp = lens1 - 1;
while(s1[pp] == '0'){
s1[pp] = '9';
pp--;
}
s1[pp]--;
if(s1[0] == '0' && lens1 > 1){
for(int i = 1; i < lens1; i++){
s1[i - 1] = s1[i];
}
s1[lens1 - 1] = '\0';
}
// cout << s1 << endl;
ll ans1 = ac.solve(s1);
ll ans2 = ac.solve(s2);
ll ans = ((ans2 - ans1) % MOD + MOD) % MOD;
printf("%lld\n", ans);
}
return 0;
}
ZOJ 3494 BCD Code(AC自动机 + 数位DP)题解的更多相关文章
- ZOJ 3494 BCD Code(AC自动机+数位DP)
BCD Code Time Limit: 5 Seconds Memory Limit: 65536 KB Binary-coded decimal (BCD) is an encoding ...
- zoj3494 BCD Code(AC自动机+数位dp)
Binary-coded decimal (BCD) is an encoding for decimal numbers in which each digit is represented by ...
- zoj3494BCD Code(ac自动机+数位dp)
l链接 这题想了好一会呢..刚开始想错了,以为用自动机预处理出k长度可以包含的合法的数的个数,然后再数位dp一下就行了,写到一半发现不对,还要处理当前走的时候是不是为合法的,这一点无法移到trie树上 ...
- 【HDU3530】 [Sdoi2014]数数 (AC自动机+数位DP)
3530: [Sdoi2014]数数 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 682 Solved: 364 Description 我们称一 ...
- 【bzoj3530】[Sdoi2014]数数 AC自动机+数位dp
题目描述 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串.例如当S=(22,333,0233)时,233是幸运数,2333.20233.3223不是幸运 ...
- BZOJ 3530 [SDOI2014]数数 (Trie图/AC自动机+数位DP)
题目大意:略 裸的AC自动机+数位DP吧... 定义f[i][x][0/1]表示已经匹配到了第i位,当前位置是x,0表示没到上限,1到上限,此时数是数量 然而会出现虚拟前导零,即前几位没有数字的情况, ...
- BCD Code ZOJ - 3494 AC自动机+数位DP
题意: 问A到B之间的所有整数,转换成BCD Code后, 有多少个不包含属于给定病毒串集合的子串,A,B <=10^200,病毒串总长度<= 2000. BCD码这个在数字电路课上讲了, ...
- 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 ...
随机推荐
- [Usaco2007 Dec]Building Roads 修建道路
题目描述 Farmer John最近得到了一些新的农场,他想新修一些道路使得他的所有农场可以经过原有的或是新修的道路互达(也就是说,从任一个农场都可以经过一些首尾相连道路到达剩下的所有农场).有些农场 ...
- .NET Core 问题记录
前言: 最近在项目中遇到了遇到了写部署步骤过多的问题,为了减少.net core项目部署步骤:需要对一些基础问题进行验证: 如端口设置.单页应用程序(angluar)合并部署方式等相关问题,特将解决过 ...
- IDEA_2019.1版本中Protobuf的使用
一.Protobuf是什么 Protobuf 是 Google 发布的开源项目,全称 Google Protocol(/'prəʊtəkɒl/,协议,草案) Buffers,是一种轻便高效的结构化数据 ...
- calc, support, media各自的含义及用法?
@support主要是用于检测浏览器是否支持CSS的某个属性,其实就是条件判断,如果支持某个属性,你可以写一套样式,如果不支持某个属性,你也可以提供另外一套样式作为替补. calc() 函数用于动态计 ...
- WPF显示命名空间不存在对应名称
3个办法 1 切换到Release模式,再生成.生成成功后切换回Debug模式就不报错了.这是Release模式下找不到我们自定义的控件导致的报错.所以切换为Release后生成则可以解决此问题. 2 ...
- Golang--Directional Channel(定向通道)
Directional Channel 通道可以是定向的(directional).在默认情况下,通道将以双向的(bidirectional)形式运作,用户既可以把值放人通道,也可以从通道取出值;但是 ...
- Redis常见配置文件详解
Redis常见配置文件详解 # vi redis.conf 1 2 3 daemonize yes #是否以后台进程运行 4 5 pidfile /var/run/redis/redis-server ...
- C - Door Man(欧拉回路_格式控制)
现在你是一个豪宅的管家,因为你有个粗心的主人,所以需要你来帮忙管理,输入会告诉你现在一共有多少个房间,然后会告诉你从哪个房间出发,你的任务就是从出发的房间通过各个房间之间的通道,来把所有的门都关上,然 ...
- 《C++ Primer》Chapter 7 [类]
前言 在C++中,我们使用类定义自己得数据类型/通过定义新的类型来反应待解决的题的各种概念,是我们更容易编写.调试和修改程序. 我们需要主要关注数据抽象的重要性.数据抽象能帮助我们将对象的具体实现与对 ...
- 2019牛客多校 Round4
Solved:3 Rank:331 B xor 题意:5e4个集合 每个集合最多32个数 5e4个询问 询问l到r个集合是不是都有一个子集的xor和等于x 题解:在牛客多校第一场学了线性基 然后这个题 ...