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;elsenode[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; }
转载于:https://www.cnblogs.com/KirinSB/p/11199789.html
ZOJ 3494 BCD Code(AC自动机 + 数位DP)题解相关推荐
- ZOJ-3494 BCD Code (ac自动机+数位dp)
题目链接 Problem Description Binary-coded decimal (BCD) is an encoding for decimal numbers in which each ...
- zoj3494BCD Code(ac自动机+数位dp)
l链接 这题想了好一会呢..刚开始想错了,以为用自动机预处理出k长度可以包含的合法的数的个数,然后再数位dp一下就行了,写到一半发现不对,还要处理当前走的时候是不是为合法的,这一点无法移到trie树上 ...
- 【HDU3530】 [Sdoi2014]数数 (AC自动机+数位DP)
3530: [Sdoi2014]数数 Time Limit: 10 Sec Memory Limit: 512 MB Submit: 682 Solved: 364 Description 我们称 ...
- 【bzoj3530】[Sdoi2014]数数 AC自动机+数位dp
题目描述 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串.例如当S=(22,333,0233)时,233是幸运数,2333.20233.3223不是幸运 ...
- 【BZOJ3530】数数(SDOI2014)-AC自动机+数位DP
测试地址:数数 做法:本题需要用到AC自动机+数位DP. 首先看到多模式串匹配,自然想到用AC自动机来做.用AC自动机构造出状态转移图后,令f(i,j,k)f(i,j,k)f(i,j,k)为匹配了最高 ...
- ZOJ 3494 BCD code
BCD code 题解 -> 传送门 ### AC自动机请滚蛋 , 而是真正的字符串\(dp\)+数位\(dp\) 注意到所有的数位\(dp\) , 都是从首位开始加数字的 , 那么在每一次加入 ...
- Censored! POJ - 1625 AC自动机+大数DP
题意: 给出一n种字符的字典,有p个禁用的单词, 问能组成多少个不同的长度为m的合法字符串.(m<=50) 题解: 是不是个我们之前做的题目非常非常像,题意都一样. 直接将上次写的AC自动机+矩 ...
- AC自动机 + 概率dp + 高斯消元 --- HDU 5955 or 2016年沈阳icpc H [AC自动机 + 概率dp + 高斯消元]详解
题目链接 题目大意: 就是有NNN个人,每个人都会猜一个长度为LLL的只包含{1,2,3,4,5,6}\{1,2,3,4,5,6\}{1,2,3,4,5,6}的序列,现在裁判开始投掷骰子,并且把每次的 ...
- HDU3247 Resource Archiver(AC自动机+BFS+DP)
题目,求最短的包含所有n个DNA片段且不包含任何一个病毒片段的序列. 容易用所有DNA片段和病毒片段建一个AC自动机,构造fail时处理一下各个结点后缀是DNA或者病毒的情况,然后dp[S][u]表示 ...
- 【BZOJ2553】禁忌,AC自动机+期望DP+矩乘
传送门 先考虑选最多禁忌串的问题 感受一下,如果禁忌串之间没有包含关系,一定是可以从前往后贪心搞的,直接建AC自动机跑匹配,找到一个禁忌串的末尾就回到根上,并把禁忌串数量+1 (所以起初我想的是把包含 ...
最新文章
- php导出页面word,php导出生成word的方法_PHP
- QT的QHttpMultiPart类的使用
- android service交互,Android Activity与Service的交互方式
- 【HDU - 6203】ping ping ping(lca+贪心思想,对lca排序,树状数组差分)
- 后通用芯片时代: 专用芯片兴起背后的经济学
- 《Python游戏趣味编程》 第4章 疯狂的小圆圈
- linux如何使用鼠标数据的,浅析linux中鼠标数据读取
- VB / VS 多语言软件设计
- 关于NDK及安装使用
- bootstrap 文字不换行
- 4个月掌握核心技术 成为云计算行业专家
- 模拟win10系统开机加载的动画
- NCBI Genbank核苷酸序列数据库检索基因序列解读
- Delphi 10.4.1 游戏开发引擎unDelphiX
- 泛微OA-流程存储数据说明(表单主表+明细表)
- 华为手机NFC模拟加密的门禁卡详细教程
- Openwrt 18.06 iPhone XR usb tethering导致内核崩溃问题解决方案
- Notion,这应该是程序员最后一款笔记软件
- win7 64位 32位旗舰版下载
- python 读写h5py文件(转载)