正着难想,要处理如何容斥,那就反着来
记
f[i][j]
f
[
i
]
[
j
]
为当前为随机串的第i位 匹配AC自动机里编号为j的点
那么答案就是
26m−∑f[m][j]
26
m
−
∑
f
[
m
]
[
j
]
写了快速幂甚至比没写还慢了一丢丢……
/**************************************************************
Problem: 1030
User: YJMSTR
Language: C++
Result: Accepted
Time:92 ms
Memory:3852 kb
****************************************************************/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define Max(_A,_B) (_A>_B?_A:_B)
#define Min(_A,_B) (_A<_B?_A:_B)
int read(){
int s = 0;bool f = 1;char c = getchar();
while(c > '9' || c < '0'){if(c == '-') f = 0; c = getchar();}
while(c >= '0' && c <= '9') {
s = s * 10 + c - '0';
c = getchar();
}
return f == 1 ? s : -s;
}
const int maxn = 6001, maxc = 26, md = 10007;
char s[101];
/*
统计答案:同时出现多个字符串 要容斥
f[i][j]:在Trie图上走i步,匹配第j个结点的方案数
f[i][j] -> f[i + 1][son[j]]
*/
int f[101][6001], n, m, a, b;
struct AC_Automaton {
int ch[maxn][maxc], fail[maxn], q[maxn], qh, qt, tot;
bool leaf[maxn];
void init(){
memset(ch, -1, sizeof(ch));
memset(fail, 0 ,sizeof(fail));
memset(leaf, 0, sizeof(leaf));
tot = 0;
}
void insert(char *str){
int p = 0;
for(int i = 0; str[i]; ++i) {
if(ch[p][str[i] - 'A'] == -1) ch[p][str[i] - 'A'] = ++tot;
p = ch[p][str[i] - 'A'];
}
leaf[p] = true;//叶子结点
}
void build(){
qh = qt = 0;
for(int i = 0; i < maxc; i++) {
if(ch[0][i] == -1) ch[0][i] = 0;
else q[qt++] = ch[0][i];
}
while(qh < qt) {
int p = q[qh++];
for(int i = 0; i < maxc; i++) {
if(ch[p][i] == -1) ch[p][i] = ch[fail[p]][i];
else {
fail[ch[p][i]] = ch[fail[p]][i];
leaf[ch[p][i]] |= leaf[fail[ch[p][i]]];
q[qt++] = ch[p][i];
}
}
}
}
void dp(){
//枚举ac自动机上的所有结点,叶子结点都是合法的
//正难则反,记数所有不合法状态种数拿去减
f[0][0] = b = 1;
for(int i = 1; i <= m; i++) {
for(int j = 0; j <= tot; j++) {
if(leaf[j] || !f[i - 1][j]) continue;
for(int k = 0; k < maxc; k++)
f[i][ch[j][k]] = (f[i][ch[j][k]] + f[i - 1][j]) % md;
}
}
for(int i = 0; i <= tot; i++) if(!leaf[i]) a = (a + f[m][i]) % md;
for(int i = 1; i <= m; i++) b = (b * maxc) % md;//总方案数,不用快速幂了
}
}ac;
int main(){
n = read(), m = read();
ac.init();
for(int i = 1; i <= n; i++) {
scanf("%s", s);
ac.insert(s);
}
ac.build();
ac.dp();
printf("%d\n", (b - a + md) % md);
return 0;
}