[JSOI2007]文本生成器
容斥原理, 求出所有的情况减去不可读的情况就是可读的文本数了a
找不可读文本的数量类似于病毒那一题趴我觉得
DP转移的话...
用f[i][j] 表示当前在节点j, 且串长为i时的情况
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e4 + 7;
const int N = 20005;
int n, m, cnt;
int f[N][10000];//f[i][j] : 当前在节点j, 且串长为i时的情况
struct {
int vis[26];
int fail;
int end;
} AC[N];
void build(string s) {
int now = 0;
for(int i = 0; i < s.size(); i++) {
if(!AC[now].vis[s[i] - 'A'])
AC[now].vis[s[i] - 'A'] = ++cnt;
now = AC[now].vis[s[i] - 'A'];
}
AC[now].end = 1;
}
void Get_fail() {
queue<int> q;
for(int i = 0; i < 26; i++)
if(AC[0].vis[i]) {
AC[AC[0].vis[i]].fail = 0;
q.push(AC[0].vis[i]);
}
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = 0; i < 26; i++) {
if(AC[u].vis[i]) {
AC[AC[u].vis[i]].fail = AC[AC[u].fail].vis[i];
AC[AC[u].vis[i]].end |= AC[AC[AC[u].vis[i]].fail].end;
q.push(AC[u].vis[i]);
}
else AC[u].vis[i] = AC[AC[u].fail].vis[i];
}
}
}
int main() {
ios :: sync_with_stdio(0);
string s;
cin >> n >> m;
for(int i = 1; i <= n; i++)
cin >> s, build(s);
Get_fail();
f[0][0] = 1;
for(int i = 1; i <= m; i++)
for(int j = 0; j <= cnt; j++)
for(int k = 0; k < 26; k++)
if(!AC[AC[j].vis[k]].end)
(f[i][AC[j].vis[k]] += f[i - 1][j] ) %= MOD;
int ans = 0;
for(int i = 0; i <= cnt; i++)
(ans += f[m][i] ) %= MOD;
int sum = 26;
for(int i = 1; i < m; i++)
(sum *= 26) %= MOD;
cout << (sum - ans + MOD) % MOD;
return 0;
}