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 ...
随机推荐
- Prometheus 重新标签
Prometheus 重新标签 允许在采集之前对任何目标及其标签进行修改 • 重命名标签名 • 删除标签 • 过滤目标 action:重新标签动作 replace:默认,通过regex匹配source ...
- Promise实现子组件的多表单校验并反馈结果给父组件
全手打原创,转载请标明出处:https://www.cnblogs.com/dreamsqin/p/11529207.html,多谢,=.=~ 本文中多表单验证主要用到Promise.all()实现多 ...
- ASP.NET Core应用程序容器化、持续集成与Kubernetes集群部署(一)(转载)
本文结构 ASP.NET Core应用程序的构建 ASP.NET Core应用程序容器化所需注意的问题 应用程序的配置信息 端口侦听 ASP.NET Core的容器版本 docker镜像构建上下文(B ...
- 使用VBA将Excel指定单元格数据、字符串或者图表对象插入到Word模板指定书签处
准备工作: 1.首先需要提供一个word模板,并且标记好您要插入书签的位置,定义书签的命名.如图 2.模拟您要插入的Excel原始数据和图表对象 插入代码如下: Private Sub Command ...
- 根据语义来选择:value-like传副本, pointer-like传引用
★ (一个成员)变量的 创建.初始化.赋值 “默认值”:内置类型的局部变量.内置类型的成员变量(未设置=initval;) 没有默认值! 若创建时不指定值,则不进行初始化.则其值未定义!!! “指定 ...
- Weyland-Energy 说明
Weyland-Energy 说明 品名:Weyland-Energy 大脑能量补充剂功能:提神.提高注意力服用方法:建议饭后1颗,一天1次或者2次,间隔4-6小时,一天不要超过4片. 成分:每2颗含 ...
- python爬虫---CrawlSpider实现的全站数据的爬取,分布式,增量式,所有的反爬机制
CrawlSpider实现的全站数据的爬取 新建一个工程 cd 工程 创建爬虫文件:scrapy genspider -t crawl spiderName www.xxx.com 连接提取器Link ...
- 【开发笔记】-Tomcat启动时设置Jdk版本
1. Window版本Tomcat 到bin下的setclasspath.bat文件,在文件的开始处添加如下代码: set JAVA_HOME=D:\Program Files\Java\jdk1.8 ...
- 学习笔记之自然语言处理(Natural Language Processing)
自然语言处理 - 维基百科,自由的百科全书 https://zh.wikipedia.org/wiki/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7 ...
- 阿里sentinel源码研究深入
1. 阿里sentinel源码研究深入 1.1. 前言 昨天已经把sentinel成功部署到线上环境,可参考我上篇博文,该走的坑也都走了一遍,已经可以初步使用它的限流和降级功能,根据我目前的实践,限流 ...