「刷题记录」[JSOI2007] 文本生成器
第一道 AC 自动机 + DP 题。
题目链接:P4052 [JSOI2007] 文本生成器 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
利用容斥原理的思想,答案就是所有串的数量减去不可读的串的数量。
设 \(dp \left(i, j \right)\) 表示串长为 \(i\),在 AC 自动机上走到编号为 \(j\) 时不经过单词结尾的路径条数。
转移方程:
该节点不是单词结尾状态:dp[i][ac[j].tr[c]] += dp[i - 1][j] % mod
这类题的状态十分固定,一般为 \(dp \left (i, j \right )\),表示串长为 \(i\),状态为 \(j\) 的情况。
代码:
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 110;
const int M = 10010;
const int mod = 1e4 + 7;
int n, m, tot;
char s[N];
int dp[N][6010];
queue<int> q;
struct node {
int fail, End;
int tr[26];
} ac[M];
void Insert(char* s) {
int l = strlen(s), u = 0;
for (int i = 0; i < l; ++ i) {
if (!ac[u].tr[s[i] - 'A']) {
ac[u].tr[s[i] - 'A'] = ++ tot;
}
u = ac[u].tr[s[i] - 'A'];
}
ac[u].End = 1;
}
void get_fail() {
for (int i = 0; i < 26; ++ i) {
if (ac[0].tr[i]) {
ac[ac[0].tr[i]].fail = 0;
q.emplace(ac[0].tr[i]);
}
}
while (!q.empty()) {
int fr = q.front();
q.pop();
for (int i = 0; i < 26; ++ i) {
if (ac[fr].tr[i]) {
ac[ac[fr].tr[i]].fail = ac[ac[fr].fail].tr[i];
ac[ac[fr].tr[i]].End |= ac[ac[ac[fr].tr[i]].fail].End;
q.emplace(ac[fr].tr[i]);
} else {
ac[fr].tr[i] = ac[ac[fr].fail].tr[i];
}
}
}
}
ll qpow(int x, int y) {
ll ans = 1;
while (y) {
if (y & 1) {
ans = ans * x % mod;
}
y >>= 1;
x = x * x % mod;
}
return ans % mod;
}
int main() {
n = read<int>(), m = read<int>();
for (int i = 1; i <= n; ++ i) {
scanf("%s", s + 1);
Insert(s + 1);
}
get_fail();
dp[0][0] = 1;
for (int i = 1; i <= m; ++ i) {
for (int j = 0; j <= tot; ++ j) {
for (int k = 0; k < 26; ++ k) {
if (!ac[ac[j].tr[k]].End) {
dp[i][ac[j].tr[k]] = (dp[i - 1][j] + dp[i][ac[j].tr[k]]) % mod;
}
}
}
}
ll ans = qpow(26, m);
for (int i = 0; i <= tot; ++ i) {
ans = ((ans - dp[m][i]) % mod + mod) % mod;
}
printf("%lld\n", ans);
return 0;
}
朝气蓬勃 后生可畏