Problem E: Passwords

\[Time Limit: 1 s \quad Memory Limit: 256 MiB
\]

题意

给出两个正整数\(A,B\),再给出\(n\)个字符串,然后问你满足条件的字符串有多少种,最后答案\(\%1e6+3\)。条件如下

\[\begin{aligned}
1、&长度在A到B之间\\
2、&所有子串不存在n个字符串中任意一个\\
3、&模式串中,把0看成o,1看成i,3看成e,5看成s,7看成t\\
4、&至少存在一个小写字母,一个大写字母,一个数字
\end{aligned}
\]

要注意一下题目中的Additionally, for the purposes of avoiding the blacklist, you cannot use \(l33t\).这句话,我一开始还以为\(l33t\)也算第\(n+1\)个字符串,也不能计数,结果发现读错了,这句话只是引出后面那么限制条件。

思路

很显然这种在多个字符串上跳来跳去的,然后给出一些限制条件,在\(AC自动机\)上\(DP\)大部分情况下是\(ok\)的,而且对\(fail\)指针\(build\)时,也很常见,补全成\(Trie\)图,把\(fail[u]\)的信息传给\(u\)就可以了。

那么如何\(dp\)呢,用\(dp[state][i][j]\),\(state\)最大为\(7\),第一位为小写字母,第二问为大写字母,第三次为数字,状压状态,\(i\)表示匹配串已经到了第\(i\)位,\(j\)表示在\(AC自动机\)上的状态,然后状态就很容易得到了。

\[\begin{aligned}
dp[st][i][j] &-> dp[st|1][i+1][k] 小写字母时\\
dp[st][i][j] &-> dp[st|2][i+1][k] 大写字母时\\
dp[st][i][j] &-> dp[st|4][i+1][k] 数字时\\
\end{aligned}
\]

最后输出\(dp[7][\sum_A^B][\sum_1^{sz}]\)就可以了。

  1. /***************************************************************
  2. > File Name : E.cpp
  3. > Author : Jiaaaaaaaqi
  4. > Created Time : 2019年05月08日 星期三 15时00分56秒
  5. ***************************************************************/
  6. #include <map>
  7. #include <set>
  8. #include <list>
  9. #include <ctime>
  10. #include <cmath>
  11. #include <stack>
  12. #include <queue>
  13. #include <cfloat>
  14. #include <string>
  15. #include <vector>
  16. #include <cstdio>
  17. #include <bitset>
  18. #include <cstdlib>
  19. #include <cstring>
  20. #include <iostream>
  21. #include <algorithm>
  22. #define lowbit(x) x & (-x)
  23. #define mes(a, b) memset(a, b, sizeof a)
  24. #define fi first
  25. #define se second
  26. #define pii pair<int, int>
  27. typedef unsigned long long int ull;
  28. typedef long long int ll;
  29. const int maxn = 5e3 + 10;
  30. const int maxm = 1e5 + 10;
  31. const ll mod = 1e6 + 3;
  32. const ll INF = 1e18 + 100;
  33. const int inf = 0x3f3f3f3f;
  34. const double pi = acos(-1.0);
  35. const double eps = 1e-8;
  36. using namespace std;
  37. int n, m, A, B;
  38. int cas, tol, T;
  39. map<int, int> mp;
  40. void handle() {
  41. mp.clear();
  42. for(int i='a'; i<='z'; i++) {
  43. mp[i] = i-'a'+1;
  44. }
  45. for(int i='A'; i<='Z'; i++) {
  46. mp[i] = i-'A'+1;
  47. }
  48. int cnt = 26;
  49. for(int i='0'; i<='9'; i++) {
  50. if(i=='0') mp[i] = mp['o'];
  51. else if(i == '1') mp[i] = mp['i'];
  52. else if(i == '3') mp[i] = mp['e'];
  53. else if(i == '5') mp[i] = mp['s'];
  54. else if(i == '7') mp[i] = mp['t'];
  55. else mp[i] = ++cnt;
  56. }
  57. }
  58. struct AC {
  59. int node[maxn][35], fail[maxn], cnt[maxn];
  60. ll dp[10][25][maxn];
  61. int root, sz;
  62. int newnode() {
  63. mes(node[++sz], 0);
  64. cnt[sz] = 0;
  65. return sz;
  66. }
  67. void init() {
  68. sz = 0;
  69. root = newnode();
  70. }
  71. void insert(char *s) {
  72. int len = strlen(s+1);
  73. int rt = root;
  74. for(int i=1; i<=len; i++) {
  75. int k = mp[s[i]];
  76. if(node[rt][k] == 0) node[rt][k] = newnode();
  77. rt = node[rt][k];
  78. }
  79. cnt[rt] = 1;
  80. }
  81. void build() {
  82. queue<int> q;
  83. while(!q.empty()) q.pop();
  84. fail[root] = root;
  85. for(int i=1; i<=31; i++) {
  86. if(node[root][i] == 0) {
  87. node[root][i] = root;
  88. } else {
  89. fail[node[root][i]] = root;
  90. q.push(node[root][i]);
  91. }
  92. }
  93. while(!q.empty()) {
  94. int u = q.front();
  95. cnt[u] |= cnt[fail[u]];
  96. q.pop();
  97. for(int i=1; i<=31; i++) {
  98. if(node[u][i] == 0) {
  99. node[u][i] = node[fail[u]][i];
  100. } else {
  101. fail[node[u][i]] = node[fail[u]][i];
  102. q.push(node[u][i]);
  103. }
  104. }
  105. }
  106. }
  107. ll solve(int A, int B) {
  108. for(int i=0; i<=7; i++) {
  109. for(int j=0; j<=B; j++) {
  110. for(int k=0; k<=sz; k++) {
  111. dp[i][j][k] = 0;
  112. }
  113. }
  114. }
  115. dp[0][0][1] = 1;
  116. for(int i=0; i<B; i++) {
  117. for(int j=1; j<=sz; j++) {
  118. if(cnt[j]) continue;
  119. for(int st=0; st<=7; st++) {
  120. if(dp[st][i][j] == 0) continue;
  121. // printf("dp[%d][%d][%d] = %lld\n", st, i, j, dp[st][i][j]);
  122. for(int k='a'; k<='z'; k++) {
  123. int nst = node[j][mp[k]];
  124. if(cnt[nst]) continue;
  125. dp[st|1][i+1][nst] += dp[st][i][j];
  126. dp[st|2][i+1][nst] += dp[st][i][j];
  127. dp[st|1][i+1][nst] %= mod;
  128. dp[st|2][i+1][nst] %= mod;
  129. }
  130. for(int k='0'; k<='9'; k++) {
  131. int nst = node[j][mp[k]];
  132. if(cnt[nst]) continue;
  133. dp[st|4][i+1][nst] += dp[st][i][j];
  134. dp[st|4][i+1][nst] %= mod;
  135. }
  136. }
  137. }
  138. }
  139. ll ans = 0;
  140. for(int i=A; i<=B; i++) {
  141. for(int j=1; j<=sz; j++) {
  142. if(dp[7][i][j] == 0) continue;
  143. // printf("dp[7][%d][%d] = %lld\n", i, j, dp[7][i][j]);
  144. ans = (ans + dp[7][i][j])%mod;
  145. }
  146. }
  147. return ans;
  148. }
  149. } ac;
  150. char s[maxn];
  151. int main() {
  152. handle();
  153. ac.init();
  154. scanf("%d%d", &A, &B);
  155. scanf("%d", &n);
  156. for(int i=1; i<=n; i++) {
  157. scanf("%s", s+1);
  158. ac.insert(s);
  159. }
  160. ac.build();
  161. ll ans = ac.solve(A, B);
  162. printf("%lld\n", ans);
  163. return 0;
  164. }

Passwords Gym - 101174E (AC自动机上DP)的更多相关文章

  1. 【洛谷4045】[JSOI2009] 密码(状压+AC自动机上DP)

    点此看题面 大致题意: 给你\(n\)个字符串,问你有多少个长度为\(L\)的字符串,使得这些字符串都是它的子串.若个数不大于\(42\),按字典序输出所有方案. 状压 显然,由于\(n\)很小,我们 ...

  2. bzoj [Sdoi2014]数数 AC自动机上dp

    [Sdoi2014]数数 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1264  Solved: 636[Submit][Status][Discu ...

  3. 【Luogu】P3311数数(AC自动机上DP)

    题目链接 蒟蒻今天终于学会了AC自动机,感觉很稳 (后一句愚人节快乐) 这题开一个f[i][j][k]表示有没有受到限制,正在枚举第j位,来到了AC自动机的第k个节点 的方案数 随后可以刷表更新 注意 ...

  4. URAL 1158 AC自动机上的简单DP+大数

    题目大意 在一种语言中的字母表中有N(N<=50)个字母,每个单词都由M(M<=50)个字母构成,因此,一共可以形成N^M个单词.但是有P(P<=10)个串是被禁止的,也就是说,任何 ...

  5. bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp)

    bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp) bzoj Luogu 题解时间 给两个小写字母串 $ A $ , $ B $ ,请你计算: ...

  6. POJ 3691 AC自动机上的dp

    题目大意: 给定一些不合理的DNA序列,再给一段较长的dna序列,问最少修改几次可以使序列中不存在任何不合理序列,不能找到修改方法输出-1 这里你修改某一个点的DNA可能会影响后面,我们不能单纯的找匹 ...

  7. HNU 13108-Just Another Knapsack Problem (ac自动机上的dp)

    题意: 给你一个母串,多个模式串及其价值,求用模式串拼接成母串(不重叠不遗漏),能获得的最大价值. 分析: ac自动机中,在字典树上查找时,用dp,dp[i]拼成母串以i为结尾的子串,获得的最大价值, ...

  8. 【BZOJ1030】[JSOI2007] 文本生成器(AC自动机上跑DP)

    点此看题面 大致题意: 给你\(N\)个字符串(只含大写字母),要你求出有多少个由\(M\)个大写字母构成的字符串含有这\(N\)个字符串中的至少一个. \(AC\)自动机 看到题目,应该比较容易想到 ...

  9. BZOJ 1030 文本生成器 | 在AC自动机上跑DP

    题目: http://www.lydsy.com/JudgeOnline/problem.php?id=1030 题解: 鸽 #include<cstdio> #include<al ...

随机推荐

  1. Sitecore 6.4 升级Sitecore 8.2.7准备

    考虑Sitecore升级?尽管这可能是一项令人生畏的任务,但这三个技巧可以帮助您无缝地完成整个过程. 如果您当前正在运行较旧版本的Sitecore并希望升级到最新版本,那么您可能已经瞥了一眼说明,但却 ...

  2. Golang读取并修改非主流配置文件

    今天工作中碰到的问题,要求修改此配置文件,没看出来是什么格式,用了下面的思路: mysql { # If any of the files below are set, TLS encryption ...

  3. 【转】AXI_Lite 总线详解

    目录: · 1.前言 · 2.AXI总线与ZYNQ的关系 · 3 AXI 总线和 AXI 接口以及 AXI 协议 · 3.1 AXI 总线概述 · 3.2 AXI 接口介绍 ·3.3 AXI 协议概述 ...

  4. 基于TCP实现的Socket通讯详解

    Socket通信是基于TCP协议进行的传输层通信,是在应用和应用之间的通信,一般应用在即时通讯上. 建立连接 用Socket创建连接需要在客户端和服务端都使用socket套接字. Linux内存创建S ...

  5. 数据结构与算法5—KMP算法

    串的模式匹配算法 子串(模式串)的定位操作通常称为串的模式匹配. 这是串的一种重要操作,很多 软件,若有“编辑”菜单项的话, 则其中必有“查找”子菜单项. 串的顺序存储实现 #include<s ...

  6. Echarts实现Excel趋势线和R平方计算思路

    测试数据 [19550, 7.1 ],[22498, 8.44 ],[25675, 9.56 ],[27701, 10.77],[29747, 11.5 ],[32800, 12.27],[34822 ...

  7. Mycat配置项详解

     schema.xml文件配置中的balance属性和writeType属性: . balance=", 不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上. . ba ...

  8. H3C 802.11 WEP加密特点与注意事项

  9. 接口测试“八重天”---RestAssured

    要记住每一个对你好的人,因为他们本可以不那么做. ---久节奏,慢读书 一.什么是RestAssured 偶然在逛帖子的时候发现一个接口测试框架,觉得不错,学习学习. 官方地址:http://rest ...

  10. 使用MPU6050陀螺仪自制Arduino数字量角器

    MPU6050惯性单元是一个3轴加速度计和一个3轴陀螺仪组合的单元.它还包含温度传感器和DCM,可执行复杂的任务. MPU6050通常用于制作无人机和其他远程控制机器人,如自平衡机器人.在本篇文章中, ...