P4052 [JSOI2007]文本生成器
链接
思路
显然可读文本数量等于总数量减去不可读的数量。先建出AC自动机,然后令
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示到达编号为
j
j
j 的结点的长度为
i
i
i 的不匹配串数量就可以了。由于一些单词可能是另一些的子串,所以 build 的时候不要忘了加 tr[now].cnt |= tr[tr[now].fail].cnt;。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 9;
const int maxm = 100 + 9;
const ll mod = 1e4 + 7;
struct tnode {
int ch[26];
int cnt, fail;
};
int n, m;
namespace AC {
tnode tr[maxn];
int tot;
void insert(const string &s) {
int len = s.length(), now = 0;
for (int i = 0; i < len; ++i) {
int c = s[i] - 'A';
if (!tr[now].ch[c])
tr[now].ch[c] = ++tot;
now = tr[now].ch[c];
}
tr[now].cnt++;
}
void build() {
queue<int> q;
for (int i = 0; i < 26; ++i) {
if (tr[0].ch[i]) {
tr[tr[0].ch[i]].fail = 0;
q.push(tr[0].ch[i]);
}
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < 26; ++i) {
int &now = tr[u].ch[i];
if (now) {
tr[now].fail = tr[tr[u].fail].ch[i];
tr[now].cnt |= tr[tr[now].fail].cnt;
q.push(now);
} else {
now = tr[tr[u].fail].ch[i];
}
}
}
}
};
ll ksm(ll b, ll k) {
ll ret = 1;
b %= mod;
while (k) {
if (k & 1)
ret = ret * b % mod;
b = b * b % mod;
k /= 2;
}
return ret;
}
using namespace AC;
ll dp[maxm][maxn];
signed main() {
cin >> n >> m;
string s;
for (int i = 1; i <= n; ++i) {
cin >> s;
insert(s);
}
build();
ll ans = ksm(26, m);
dp[0][0] = 1;
for (int i = 0; i < m; ++i) {
for (int j = 0; j <= tot; ++j) {
for (int k = 0; k < 26; ++k) {
if (!tr[tr[j].ch[k]].cnt) {
dp[i + 1][tr[j].ch[k]] = (dp[i + 1][tr[j].ch[k]] + dp[i][j]) % mod;
}
}
}
}
for (int i = 0; i <= tot; ++i)
ans = (ans - dp[m][i] + mod) % mod;
cout << ans << '\n';
return 0;
}

浙公网安备 33010602011771号