Passwords Gym - 101174E (AC自动机上DP)
Problem E: Passwords
\]
题意
给出两个正整数\(A,B\),再给出\(n\)个字符串,然后问你满足条件的字符串有多少种,最后答案\(\%1e6+3\)。条件如下
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自动机\)上的状态,然后状态就很容易得到了。
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}]\)就可以了。
/***************************************************************
> File Name : E.cpp
> Author : Jiaaaaaaaqi
> Created Time : 2019年05月08日 星期三 15时00分56秒
***************************************************************/
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pii pair<int, int>
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 5e3 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e6 + 3;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std;
int n, m, A, B;
int cas, tol, T;
map<int, int> mp;
void handle() {
mp.clear();
for(int i='a'; i<='z'; i++) {
mp[i] = i-'a'+1;
}
for(int i='A'; i<='Z'; i++) {
mp[i] = i-'A'+1;
}
int cnt = 26;
for(int i='0'; i<='9'; i++) {
if(i=='0') mp[i] = mp['o'];
else if(i == '1') mp[i] = mp['i'];
else if(i == '3') mp[i] = mp['e'];
else if(i == '5') mp[i] = mp['s'];
else if(i == '7') mp[i] = mp['t'];
else mp[i] = ++cnt;
}
}
struct AC {
int node[maxn][35], fail[maxn], cnt[maxn];
ll dp[10][25][maxn];
int root, sz;
int newnode() {
mes(node[++sz], 0);
cnt[sz] = 0;
return sz;
}
void init() {
sz = 0;
root = newnode();
}
void insert(char *s) {
int len = strlen(s+1);
int rt = root;
for(int i=1; i<=len; i++) {
int k = mp[s[i]];
if(node[rt][k] == 0) node[rt][k] = newnode();
rt = node[rt][k];
}
cnt[rt] = 1;
}
void build() {
queue<int> q;
while(!q.empty()) q.pop();
fail[root] = root;
for(int i=1; i<=31; i++) {
if(node[root][i] == 0) {
node[root][i] = root;
} else {
fail[node[root][i]] = root;
q.push(node[root][i]);
}
}
while(!q.empty()) {
int u = q.front();
cnt[u] |= cnt[fail[u]];
q.pop();
for(int i=1; i<=31; i++) {
if(node[u][i] == 0) {
node[u][i] = node[fail[u]][i];
} else {
fail[node[u][i]] = node[fail[u]][i];
q.push(node[u][i]);
}
}
}
}
ll solve(int A, int B) {
for(int i=0; i<=7; i++) {
for(int j=0; j<=B; j++) {
for(int k=0; k<=sz; k++) {
dp[i][j][k] = 0;
}
}
}
dp[0][0][1] = 1;
for(int i=0; i<B; i++) {
for(int j=1; j<=sz; j++) {
if(cnt[j]) continue;
for(int st=0; st<=7; st++) {
if(dp[st][i][j] == 0) continue;
// printf("dp[%d][%d][%d] = %lld\n", st, i, j, dp[st][i][j]);
for(int k='a'; k<='z'; k++) {
int nst = node[j][mp[k]];
if(cnt[nst]) continue;
dp[st|1][i+1][nst] += dp[st][i][j];
dp[st|2][i+1][nst] += dp[st][i][j];
dp[st|1][i+1][nst] %= mod;
dp[st|2][i+1][nst] %= mod;
}
for(int k='0'; k<='9'; k++) {
int nst = node[j][mp[k]];
if(cnt[nst]) continue;
dp[st|4][i+1][nst] += dp[st][i][j];
dp[st|4][i+1][nst] %= mod;
}
}
}
}
ll ans = 0;
for(int i=A; i<=B; i++) {
for(int j=1; j<=sz; j++) {
if(dp[7][i][j] == 0) continue;
// printf("dp[7][%d][%d] = %lld\n", i, j, dp[7][i][j]);
ans = (ans + dp[7][i][j])%mod;
}
}
return ans;
}
} ac;
char s[maxn];
int main() {
handle();
ac.init();
scanf("%d%d", &A, &B);
scanf("%d", &n);
for(int i=1; i<=n; i++) {
scanf("%s", s+1);
ac.insert(s);
}
ac.build();
ll ans = ac.solve(A, B);
printf("%lld\n", ans);
return 0;
}
Passwords Gym - 101174E (AC自动机上DP)的更多相关文章
- 【洛谷4045】[JSOI2009] 密码(状压+AC自动机上DP)
点此看题面 大致题意: 给你\(n\)个字符串,问你有多少个长度为\(L\)的字符串,使得这些字符串都是它的子串.若个数不大于\(42\),按字典序输出所有方案. 状压 显然,由于\(n\)很小,我们 ...
- bzoj [Sdoi2014]数数 AC自动机上dp
[Sdoi2014]数数 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1264 Solved: 636[Submit][Status][Discu ...
- 【Luogu】P3311数数(AC自动机上DP)
题目链接 蒟蒻今天终于学会了AC自动机,感觉很稳 (后一句愚人节快乐) 这题开一个f[i][j][k]表示有没有受到限制,正在枚举第j位,来到了AC自动机的第k个节点 的方案数 随后可以刷表更新 注意 ...
- URAL 1158 AC自动机上的简单DP+大数
题目大意 在一种语言中的字母表中有N(N<=50)个字母,每个单词都由M(M<=50)个字母构成,因此,一共可以形成N^M个单词.但是有P(P<=10)个串是被禁止的,也就是说,任何 ...
- bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp)
bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp) bzoj Luogu 题解时间 给两个小写字母串 $ A $ , $ B $ ,请你计算: ...
- POJ 3691 AC自动机上的dp
题目大意: 给定一些不合理的DNA序列,再给一段较长的dna序列,问最少修改几次可以使序列中不存在任何不合理序列,不能找到修改方法输出-1 这里你修改某一个点的DNA可能会影响后面,我们不能单纯的找匹 ...
- HNU 13108-Just Another Knapsack Problem (ac自动机上的dp)
题意: 给你一个母串,多个模式串及其价值,求用模式串拼接成母串(不重叠不遗漏),能获得的最大价值. 分析: ac自动机中,在字典树上查找时,用dp,dp[i]拼成母串以i为结尾的子串,获得的最大价值, ...
- 【BZOJ1030】[JSOI2007] 文本生成器(AC自动机上跑DP)
点此看题面 大致题意: 给你\(N\)个字符串(只含大写字母),要你求出有多少个由\(M\)个大写字母构成的字符串含有这\(N\)个字符串中的至少一个. \(AC\)自动机 看到题目,应该比较容易想到 ...
- BZOJ 1030 文本生成器 | 在AC自动机上跑DP
题目: http://www.lydsy.com/JudgeOnline/problem.php?id=1030 题解: 鸽 #include<cstdio> #include<al ...
随机推荐
- SpringBoot:3.SpringBoot使用Spring-data-jpa实现数据库访问
做Web开发,首先要能将数据渲染到网页中展示,其次是要获取数据库数据展示到视图层,在前面的文章SpringBoot整合Thymeleaf模板引擎渲染web视图,我们实现了从后端数据展示到视图层,那么下 ...
- U9数据权限分配枚举值方法
1.配置动态视图,定位应用对应控制实体,并设置动态视图类型:读取 或 增.删.改: 2.设置动态视图条件:MOPickList.MO.DocState.Value in (FunEnum('生产订单单 ...
- 使用预编译库PREBUILT LIBRARY官方说明
使用预编译库 NDK 支持使用预编译库(同时支持静态库和共享库).此功能有以下两个主要用例: 向第三方 NDK 开发者分发您自己的库(而不分发您的源代码). 使用您自己的库的预编译版本来提升编译速度. ...
- SQL Server中COALESCE函数的用法
在SQL Server中COALESCE函数,会返回其参数中第一个不为NULL的参数,效果如下: SELECT COALESCE(NULL,NULL,N'A',NULL,NULL) 结果: SELEC ...
- Angular复习笔记7-路由(下)
Angular复习笔记7-路由(下) 这是angular路由的第二篇,也是最后一篇.继续上一章的内容 路由跳转 Web应用中的页面跳转,指的是应用响应某个事件,从一个页面跳转到另一个页面的行为.对于使 ...
- Matlab命令模式
命令模式(Command)将命令封装为对象,实现命令发送者和命令接收者的解耦.线程池.MVC框架用到了命令模式,本文根据以下类图,用matlab实现命令模式. Invoker.m (传递命令对象Inv ...
- JavaScript 之 事件(详解)
一.注册事件的三种方式 1.直接事件方式 语法格式: 变量名.on事件名 = function() {} 注意:这种方式无法给同一对象的同一事件注册多个事件处理函数 2.addEventListene ...
- Go语言入门——函数
写了快一个月的Go,已经没有什么陌生感了. 一行代码写完,不会在行尾本能的敲上“:”,直接Enter键换行: 定义变量把变量名放在前面,类型放在后面: 使用struct去定义自己想要的数据模型就好比定 ...
- tensorflow 镜像
https://mirrors.tuna.tsinghua.edu.cn/tensorflow/windows/cpu/ 报错 不支持 C:\Users\brady\.conda\envs\tenso ...
- 【数据库】数据库入门(三): SQL
SQL: 结构化查询语言(Structured Query Language) SQL 是由 IBM 公司首先开发产生,它是关系型数据库最早出现的商用语言之一.1974年,IBM 公司 San Jos ...