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 ...
随机推荐
- E2.在shell中正确退出当前表达式
E2.在shell中正确退出当前表达式 优雅退出当前表达式 在shell里面输出复杂的多行表达时,经常由于少输入一个引号,一直无法退出当前的表达式求值,也没有办法终止它,以前只能通过两次Ctrl+C结 ...
- 【汇编实践】go assembly
https://mp.weixin.qq.com/s/B577CdUkWCp_XgUc1VVvSQ asmshare/layout.md at master · cch123/asmshare htt ...
- the code has to work especially hard to keep things in the same thread
django/asgiref: ASGI specification and utilities https://github.com/django/asgiref/
- 洛谷P4180
被教练安排讲题 可恶 这道题我是十月初上课时花了一下午做出来的,当时连倍增都不会,过程比较困难,现在看看还可以 本来想口胡一发,后来想了想可能以后要用,还是写成文章吧 Description 求一棵严 ...
- SSH入门开发(实现一个简单的登录功能)详解
开头,首先想记录下一首诗,是今天拇指阅读看到的:很有感触,所以乐于分享: 那么,下面正式开始进入正题,搭建一个 SSH完整的项目: 首先,我们需要在WEB-ROOT下创建一个login.jsp(登录) ...
- Spring boot获取getBean
package com.job.center.quartz.common; import org.springframework.beans.BeansException; import org.sp ...
- svn安装步骤
我使用的是myeclipse 8.5 svn是site-1.8.22.zip 步骤 1.在myeclipse安装路径下dropins文件夹中创建svn文件夹 2.解压site-1.8.22.zip复 ...
- SSL与HTTPS协议
1.SSL 1.1 什么是SSL SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及 ...
- Latex安装教程(附美赛论文latex模板)
@ 目录 Latex简介 安装步骤 texlive下载 配置环境变量 配置Texsudio latex版本helloworld 美赛 latex模板 Latex简介 LaTeX(LATEX,音译&qu ...
- ASP.Net Core 5.0 MVC 配置文件读取,Startup 类中ConfigureServices 方法、Configure 方法的使用
配置文件读取 1. 新建FirstController控制器 在appsettings文件内容替换成以下代码 { "Position": { "Title": ...