\(\text{Analysis}\)

做了几道题后发现挺套路的

涉及统计或构造文本串与众多模式串匹配产生贡献或存在限制时的 \(DP\)

一般设 \(f[i][j]\) 表示考虑到文本串第 \(i\) 位,在自动机上的 \(j\) 位置

加上 \(j\) 这一维,把自动机的弄进 \(DP\) 里,方便处理与匹配相关的限制

下面是几道题(按我的做题顺序

\(\text{[JSOI2007]}\) 文本生成器

考虑容斥,所有的方案减去一个模式串都不能出现的方案

\(DP\) 计算一个模式串都不能出现的方案,即在自动机上不能走到模式串结尾的结点

设 \(f[i][j]\) 表示考虑到文本串第 \(i\) 位,走到自动机 \(j\) 位置时的答案

那么枚举当前位填的字母,考虑能不能填

能不能填的判断方法,就是填了之后的自动机的位置,它以及跳 \(fail\) 后遇到的结点均不能是模式串结尾的结点

这个很好理解

然后就没了

$\text{Code}$
#include <cstdio>
#include <cstring>
#define IN inline
using namespace std; const int P = 10007, N = 6005;
int n, m, size = 1;
int tr[N][26], vis[N], Q[N], fail[N], f[105][N];
char s[105]; IN void insert() {
int len = strlen(s), u = 1, c;
for(int i = 0; i < len; i++) {
c = s[i] - 'A';
if (!tr[u][c]) tr[u][c] = ++size;
u = tr[u][c];
}
vis[u] = 1;
} IN void build() {
int h = 0, t = 0;
for(int i = 0; i < 26; i++)
if (tr[1][i]) fail[Q[++t] = tr[1][i]] = 1; else tr[1][i] = 1;
while (h < t) {
int now = Q[++h];
for(int i = 0; i < 26; i++)
if (tr[now][i]) vis[tr[now][i]] |= vis[fail[tr[now][i]] = tr[fail[now]][i]], Q[++t] = tr[now][i];
else tr[now][i] = tr[fail[now]][i];
}
} IN void Add(int &x, int y) {if ((x += y - P) < 0) x += P;}
IN void Dec(int &x, int y) {if ((x -= y) < 0) x += P;} int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%s", s), insert();
build(), f[0][1] = 1;
for(int i = 0; i < m; i++)
for(int j = 1; j <= size; j++)
for(int k = 0; k < 26; k++)
if (!vis[tr[j][k]])
Add(f[i + 1][tr[j][k]], f[i][j]);
int ans = 1;
for(int i = 1; i <= m; i++) ans = 26LL * ans % P;
for(int i = 1; i <= size; i++) Dec(ans, f[m][i]);
printf("%d\n", ans);
}

\(\text{[SDOI2014]}\) 数数

尝试数位 \(DP\),发现不行

关于不能出现匹配,弄进 \(AC\) 自动机里就好了

具体设 \(f[i][j][l][k]\) 表示到了第 \(i\) 位,自动机 \(j\) 的位置上,是否有高位标记,是否有前导零

转移很显然

关于模式串的前导零,在自动机上走时,如果有前导零,那么接下来若填 \(0\),则自动机上的状态应还处于根处

因为压根就没开始。

不填 \(0\) 的话,应从根出发走到相应的儿子结点

所以我改变了下枚举顺序

不过这题数据挺垃圾的

一些奇妙的甚至错误的处理方式都能 \(AC\)

$\text{Code}$
#include <cstdio>
#include <cstring>
#define IN inline
using namespace std; const int N = 1505, P = 1e9 + 7;
int m, size, tr[N][11], fail[N], Q[N], tag[N], f[N][N][2][2], a[N];
char n[N], s[N]; IN void insert() {
int len = strlen(s), u = 0, c;
for(int i = 0; i < len; i++) {
c = s[i] - '0';
if (!tr[u][c]) tr[u][c] = ++size;
u = tr[u][c];
}
tag[u] = 1;
} IN void build() {
int h = 0, t = 0, now;
for(int i = 0; i < 10; i++) if (tr[0][i]) Q[++t] = tr[0][i];
while (h < t) {
now = Q[++h];
for(int i = 0; i < 10; i++)
if (tr[now][i]) tag[tr[now][i]] |= tag[fail[tr[now][i]] = tr[fail[now]][i]], Q[++t] = tr[now][i];
else tr[now][i] = tr[fail[now]][i];
}
} IN void Add(int &x, int y) {if ((x += y - P) < 0) x += P;}
int main() {
scanf("%s%d", n + 1, &m);
for(int i = 1; i <= m; i++) scanf("%s", s), insert();
build(), f[0][0][1][1] = 1;
int len = strlen(n + 1);
for(int i = 1; i <= len; i++) a[i] = n[i] - '0';
for(int i = 0; i < len; i++)
for(int l = 0; l < 2; l++)
for(int k = 0; k <= (l ? a[i + 1] : 9); k++) {
if (!tag[tr[0][k]]) Add(f[i + 1][k ? tr[0][k] : 0][l & (k == a[i + 1])][!k], f[i][0][l][1]);
for(int j = 0; j <= size; j++)
if (!tag[tr[j][k]]) Add(f[i + 1][tr[j][k]][l & (k == a[i + 1])][0], f[i][j][l][0]);
}
int ans = 0;
for(int i = 0; i <= size; i++)
for(int j = 0; j < 2; j++)
for(int k = 0; k < 2; k++) Add(ans, f[len][i][j][k]);
printf("%d\n", (ans - 1 + P) % P);
}

\(\text{[USACO12JAN]Video Game G}\)

这个题就一样一样的了

要初始化

$\text{Code}$
#include <cstdio>
#include <iostream>
#include <cstring>
#define IN inline
using namespace std; const int N = 305, INF = 0x3f3f3f3f;
int n, m, size;
int tag[N], tr[N][3], fail[N], Q[N], f[N << 2][N];
char s[21]; IN void insert() {
int len = strlen(s), u = 0, c;
for(int i = 0; i < len; i++) {
c = s[i] - 'A';
if (!tr[u][c]) tr[u][c] = ++size;
u = tr[u][c];
}
tag[u] = 1;
} IN void build() {
int h = 0, t = 0, now;
for(int i = 0; i < 3; i++) if (tr[0][i]) Q[++t] = tr[0][i];
while (h < t) {
now = Q[++h];
for(int i = 0; i < 3; i++)
if (tr[now][i]) tag[Q[++t] = tr[now][i]] += tag[fail[tr[now][i]] = tr[fail[now]][i]];
else tr[now][i] = tr[fail[now]][i];
}
} int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%s", s), insert();
memset(f, -INF, sizeof f);
build(), f[0][0] = 0;
for(int i = 0; i < m; i++)
for(int j = 0; j <= size; j++)
for(int k = 0; k < 3; k++)
f[i + 1][tr[j][k]] = max(f[i + 1][tr[j][k]], f[i][j] + tag[tr[j][k]]);
int ans = 0;
for(int i = 0; i <= size; i++) ans = max(ans, f[m][i]);
printf("%d\n", ans);
}

\(\text{CF808G Anthem of Berland}\)

好久没写 \(AC\) 自动机上 \(dp\) 了

然而这道题是 \(KMP\) 自动机,实际上不过是只有一个串的 \(AC\) 自动机

温习了一下写法,注意 \(fail\) 初始化!!!

根的儿子结点的 \(fail\) 要先初始化为根本身

$\text{Code}$
#include <bits/stdc++.h>
using namespace std; const int N = 1e5 + 5;
int tr[N][26], fail[N];
char s1[N], s2[N]; int main() {
scanf("%s%s", s1 + 1, s2 + 1);
int len1 = strlen(s1 + 1), len2 = strlen(s2 + 1);
for(int i = 1; i <= len2; i++) tr[i - 1][s2[i] - 'a'] = i;
for(int i = 1; i <= len2; i++)
for(int j = 0; j < 26; j++)
if (tr[i][j]) fail[tr[i][j]] = tr[fail[i]][j];
else tr[i][j] = tr[fail[i]][j];
vector<vector<int>> f(len1 + 1, vector<int>(len2 + 1, -1e9));
f[0][0] = 0;
for(int i = 0; i < len1; i++) {
for(int j = 0; j <= len2; j++) if (f[i][j] != -1e9) {
if (s1[i + 1] != '?') {
int ch = tr[j][s1[i + 1] - 'a'];
f[i + 1][ch] = max(f[i + 1][ch], f[i][j] + (ch == len2));
continue;
}
for(int k = 0; k < 26; k++)
f[i + 1][tr[j][k]] = max(f[i + 1][tr[j][k]], f[i][j] + (tr[j][k] == len2));
}
}
int ans = -1e9;
for(int i = 0; i <= len2; i++) ans = max(ans, f[len1][i]);
printf("%d\n", ans);
}

AC 自动机上 DP的更多相关文章

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

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

  2. Passwords Gym - 101174E (AC自动机上DP)

    Problem E: Passwords \[ Time Limit: 1 s \quad Memory Limit: 256 MiB \] 题意 给出两个正整数\(A,B\),再给出\(n\)个字符 ...

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

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

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

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

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

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

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

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

  7. POJ 3691 AC自动机上的dp

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

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

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

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

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

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

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

随机推荐

  1. 实践案例:同程艺龙网的 Dubbo 升级经验总结

    本篇为同程艺龙旅行网 Apache Dubbo 的实践案例总结.感兴趣的朋友可以访问官网了解更多详情,或搜索关注官方微信公众号 Apache Dubbo 跟进最新动态. 作者信息: 严浩:同程艺龙高级 ...

  2. JUC面试点汇总

    JUC面试点汇总 我们会在这里介绍我所涉及到的JUC相关的面试点内容,本篇内容持续更新 我们会介绍下述JUC的相关面试点: 线程状态 线程池 Wait和Sleep Synchronized和Lock ...

  3. 【Hadoop学习】补充:优化、新特性

    一.数据压缩 1.概述 原则:IO密集而不是计算密集的job 压缩算法选择 2.压缩位置选择 通过参数进行配置 3.压缩实例: 数据流的压缩和解压缩 Map输出端采用压缩 Reduce输出端采用压缩 ...

  4. Dart开发服务端,我是不是发烧(骚)了?

    前言 最近一段时间,我和我的团队开发了两个 APP. 客户端方面采用了 Flutter,方便跨平台. 服务端方面剑走偏锋,没有采用 php, pythod, java之类的,而是采用了与 Flutte ...

  5. JAVA学到方法写了一个四则运算计算器,请教一下有什么需要改进的

    package method; /* * 四则运算计算器 * */ import java.util.Scanner; public class Demo07 { public static void ...

  6. 异构混排在vivo互联网的技术实践

    作者:vivo 互联网算法团队- Shen Jiyi 本文根据沈技毅老师在"2022 vivo开发者大会"现场演讲内容整理而成. 混排层负责将多个异构队列的结果如广告.游戏.自然量 ...

  7. dubbo2升级到dubbo3实践

    dubbo当前版本 2.7.3 期望升级到 3.0.11. 升级过程 maven依赖变更 <dependency> <groupId>org.apache.dubbo</ ...

  8. 微软跨平台maui开发chatgpt客户端

    image 什么是maui .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架,用于使用 C# 和 XAML 创建本机移动(ios,andriod)和桌面(windows,mac)应 ...

  9. week_9(推荐系统)

    Andrew Ng 机器学习笔记 ---By Orangestar Week_9(推荐系统) 1. Problem Formulation 这节就仅仅简单地介绍了一下 推荐系统的应用和实例.完全可以略 ...

  10. python3使用OCR识别图片

    放假三天,闲来无事,想学下python爬虫.本想跟着网上教程操作一遍,奈何安装使用过程中出现一堆问题,并且在网上搜了一堆复制黏贴的答案,关键都不能起作用,最后终于找到一篇生效,为了以后不至于再经历这种 ...