题意:每位十进制数都能转化为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)题解相关推荐

  1. ZOJ-3494 BCD Code (ac自动机+数位dp)

    题目链接 Problem Description Binary-coded decimal (BCD) is an encoding for decimal numbers in which each ...

  2. zoj3494BCD Code(ac自动机+数位dp)

    l链接 这题想了好一会呢..刚开始想错了,以为用自动机预处理出k长度可以包含的合法的数的个数,然后再数位dp一下就行了,写到一半发现不对,还要处理当前走的时候是不是为合法的,这一点无法移到trie树上 ...

  3. 【HDU3530】 [Sdoi2014]数数 (AC自动机+数位DP)

    3530: [Sdoi2014]数数 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 682  Solved: 364 Description 我们称 ...

  4. 【bzoj3530】[Sdoi2014]数数 AC自动机+数位dp

    题目描述 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串.例如当S=(22,333,0233)时,233是幸运数,2333.20233.3223不是幸运 ...

  5. 【BZOJ3530】数数(SDOI2014)-AC自动机+数位DP

    测试地址:数数 做法:本题需要用到AC自动机+数位DP. 首先看到多模式串匹配,自然想到用AC自动机来做.用AC自动机构造出状态转移图后,令f(i,j,k)f(i,j,k)f(i,j,k)为匹配了最高 ...

  6. ZOJ 3494 BCD code

    BCD code 题解 -> 传送门 ### AC自动机请滚蛋 , 而是真正的字符串\(dp\)+数位\(dp\) 注意到所有的数位\(dp\) , 都是从首位开始加数字的 , 那么在每一次加入 ...

  7. Censored! POJ - 1625 AC自动机+大数DP

    题意: 给出一n种字符的字典,有p个禁用的单词, 问能组成多少个不同的长度为m的合法字符串.(m<=50) 题解: 是不是个我们之前做的题目非常非常像,题意都一样. 直接将上次写的AC自动机+矩 ...

  8. 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}的序列,现在裁判开始投掷骰子,并且把每次的 ...

  9. HDU3247 Resource Archiver(AC自动机+BFS+DP)

    题目,求最短的包含所有n个DNA片段且不包含任何一个病毒片段的序列. 容易用所有DNA片段和病毒片段建一个AC自动机,构造fail时处理一下各个结点后缀是DNA或者病毒的情况,然后dp[S][u]表示 ...

  10. 【BZOJ2553】禁忌,AC自动机+期望DP+矩乘

    传送门 先考虑选最多禁忌串的问题 感受一下,如果禁忌串之间没有包含关系,一定是可以从前往后贪心搞的,直接建AC自动机跑匹配,找到一个禁忌串的末尾就回到根上,并把禁忌串数量+1 (所以起初我想的是把包含 ...

最新文章

  1. php导出页面word,php导出生成word的方法_PHP
  2. QT的QHttpMultiPart类的使用
  3. android service交互,Android Activity与Service的交互方式
  4. 【HDU - 6203】ping ping ping(lca+贪心思想,对lca排序,树状数组差分)
  5. 后通用芯片时代: 专用芯片兴起背后的经济学
  6. 《Python游戏趣味编程》 第4章 疯狂的小圆圈
  7. linux如何使用鼠标数据的,浅析linux中鼠标数据读取
  8. VB / VS 多语言软件设计
  9. 关于NDK及安装使用
  10. bootstrap 文字不换行
  11. 4个月掌握核心技术 成为云计算行业专家
  12. 模拟win10系统开机加载的动画
  13. NCBI Genbank核苷酸序列数据库检索基因序列解读
  14. Delphi 10.4.1 游戏开发引擎unDelphiX
  15. 泛微OA-流程存储数据说明(表单主表+明细表)
  16. 华为手机NFC模拟加密的门禁卡详细教程
  17. Openwrt 18.06 iPhone XR usb tethering导致内核崩溃问题解决方案
  18. Notion,这应该是程序员最后一款笔记软件
  19. win7 64位 32位旗舰版下载
  20. python 读写h5py文件(转载)

热门文章

  1. 服务器双网卡导致的网络故障及解决方案
  2. const 使用方法具体解释
  3. 仅109美元 搞一套Evive物联网开发工具包回家耍
  4. nodejs的一些日常操作
  5. 一小时学会用Python Socket 开发可并发的FTP服务器
  6. 那些年,我们一起追的女孩。
  7. 手把手教您安全配置Apache服务器
  8. 2010年年度 “中国智能建筑品牌奖”获奖名单
  9. 京东面试官:SQL 语句中 left join 后用 on 还是 where,区别大了!
  10. 我们决定聚在一起搞件大事