P4052题解
我们来看一下这道题:
首先建出
考虑容斥,即总数 - 不可读的个数。
总数 =
问题变成 不可读的方案 有多少个?
显然,如果一个点
那么用一个
考虑 动态规划,记
最后方案就是:
注意:要取摸,且处理取摸后再减为负数的情况
具体实现,可看代码。
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 6e4 + 10, mod = 1e4 + 7;
int n, m, cnt = 1, trie[maxn][26], fail[maxn], dp[110][maxn];
char c[maxn][110];
bool flag[maxn];
queue <int> q;
void insert (int p) { // 建立 trie 树
int now = 1, len = strlen (c[p] + 1);
for (int i = 1; i <= len; ++i) {
int x = c[p][i] - 'A';
if (!trie[now][x]) trie[now][x] = ++ cnt;
now = trie[now][x];
}
flag[now] = 1;
}
void calc () { // 求出 fail 与 flag 数组,便建出 AC 自动机
for (int i = 0; i < 26; ++i) trie[0][i] = 1;
q.push (1); fail[1] = 0;
while (!q.empty()) {
int now = q.front(); q.pop();
for (int i = 0; i < 26; ++i) {
if (trie[now][i]) {
fail[trie[now][i]] = trie[fail[now]][i]; flag[trie[now][i]] |= flag[fail[trie[now][i]]];
q.push (trie[now][i]);
} else {
trie[now][i] = trie[fail[now]][i];
}
}
}
}
int query () { // 求不可行方案
dp[0][1] = 1;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= cnt; ++j) {
for (int k = 0; k < 26; ++k) {
if (!flag[trie[j][k]]) dp[i][trie[j][k]] = (dp[i][trie[j][k]] + dp[i - 1][j]) % mod;
}
}
}
int ans = 0;
for (int i = 1; i <= cnt; ++i) {ans = (ans + dp[m][i]) % mod; cout << ans << endl;}
return ans;
}
int pow (int x, int y) { // 快速幂
int res = 1;
while (y) {
if (y & 1) res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
int main() {
scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf ("%s", c[i] + 1); insert (i); // 插入
}
calc ();
printf ("%d", (pow (26, m) - query() + mod) % mod); // 容斥
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】