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 ...
随机推荐
- matlab利用m_map工具包画中国地图及散点云图
开始之前需要准备好malab,中国地图shp文件,m_map工具包. 中国地图shp文件可以在下面的链接中下载: https://gadm.org/download_country_v3.html 本 ...
- Java的常用API之Date类简介
Data类 java.util.Date:表示日期和时间的类类Date 表示特定的瞬间,精确到毫秒.毫秒:千分之一秒 1000毫秒=1秒 把日期转换成毫秒: 当前的日期:2019-07-18 时间原点 ...
- Java学习:内部类的概念于分类
内部类的概念于分类 如果一个事物的内部类包含另一个事物,那么这就是一个类内部包含另一个类.例如:身体和心脏的关系,又如:汽车和发动机的关系. 分类 成员内部类 局部内部类(包含匿名内部类) 成员内部类 ...
- golang ---查看进程(Windows)
package main import ( "fmt" "os" "os/exec" "strconv" "s ...
- 封装:简要介绍自定义开发基于WPF的MVC框架
原文:封装:简要介绍自定义开发基于WPF的MVC框架 一.目的:在使用Asp.net Core时,深感MVC框架作为页面跳转数据处理的方便,但WPF中似乎没有现成的MVC框架,由此自定义开发一套MVC ...
- C#读写修改设置调整UVC摄像头画面-滚动
有时,我们需要在C#代码中对摄像头的滚动进行读和写,并立即生效.如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄像 ...
- python基础08--迭代器,生成器
1.1 迭代器 1.可迭代对象:str,list,tuple,set,dict, 迭代器:f(文件),range() 可迭代对象和迭代器都可以for循环 可迭代对象不会计数, 迭代器会计数,上面操作到 ...
- 微信小程序生命周期详解
文章出处:https://blog.csdn.net/qq_29712995/article/details/79784222 在我看来小程序的生命周期虽然简单,但是他渗透了小程序开发的整个过程,对于 ...
- 93.vue---在vue环境用webuploader分片上传插件遇到的超级bug(独家仅此一份)
本来我是想想用vue-simple-uploader (https://www.cnblogs.com/xiahj/p/vue-simple-uploader.html)的 但是公司后台已经做好了we ...
- Vue -- 项目报错整理(2):IE报错 - ‘SyntaxError:strict 模式下不允许一个属性有多个定义‘ ,基于vue element-ui页面跳转坑的解决