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 ...
随机推荐
- Linux Centos7之由Python2升级到Python3教程
1.先查看当前系统Python版本,默认都是Python2.7,命令如下: [root@localhost gau]# python -V Python 2.7.5 2.安装Python3,安装方法很 ...
- Flask源码关于local的实现
flask源码关于local的实现 try: # 协程 from greenlet import getcurrent as get_ident except ImportError: try: fr ...
- Markdown里常用的HTML元素
转义:\ 换行:<br/> 红色文字:<font color=#FF0000>字体改成红色了</font> A标签 新窗口:<a href="xxx ...
- Vue基础之Vue的模板语法
Vue基础之Vue的模板语法 数据绑定 01 数据绑定最常见的形式就是使用插值表达式(两个大括号!)[也就是小胡子语法!mustache] <body> <!-- Vue.js的应用 ...
- 什么是STP
简介 了解STP 配置STP 相关信息 简介 STP(Spanning Tree Protocol)是运行在交换机上的二层破环协议,环路会导致广播风暴.MAC地址表震荡等后果,STP的主要目的就是确保 ...
- login shell 和 non-login shell 的相关问题
问题:通过su命令切换用户并没有进入该用户的shell环境.这是为什么? 要解决这个问题,我们必须清楚用login shell 和non-login shell的区别. login sh ...
- 设计模式(一)——Java单例模式(代码+源码分析)
1)单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能 2)当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不 ...
- 看KubeEdge携手K8S,如何管理中国高速公路上的10万边缘节点
摘要:为保证高速公路上门架系统的落地项目的成功落地,选择K8s和KubeEdge来进行整体的应用和边缘节点管理. 一.项目背景 本项目是在高速公路ETC联网和推动取消省界收费站的大前提下,门架系统的落 ...
- 「SCOI2005」互不侵犯 (状压DP)
题目链接 在\(N\times N\) 的棋盘里面放 \(K\)个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共\(8\) 个格子 ...
- 博弈论入门——Nim游戏引入
说实话,我真的对这个游戏看得是一脸懵逼,因为(我太弱了)我没有明白一些变量的意思,所以一直很懵,现在才明白,这让我明白博弈论(还可以骗钱)博大精深; 以下是我自己思考的过程,也许不严谨,但是最终明白了 ...