文本生成器加强版 (吐槽)
感觉没有什么加强。
这个题单纯的增加m大小,而在AC自动机中的节点个数还依旧是大约6000个,所以依旧不能使用矩阵快速幂进行优化,就正常的计算即可。
同样是通过暴力枚举,进行dp出来不存在这写字符串的数的个数,然后使用总数减去。
注意AC自动机建完之后,用fail拓扑序来进行一次递推。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std ;
using ll = long long ;
using pii = pair<int,int> ;
const int N = 6100 ;
const int mod = 10007 ;
int n,m ;
char s[N] ;
int f[2][N] ; // dp的滚动数组
namespace Acam{ // Ac自动机
int tr[N][26],ne[N],idx ;
int q[N] ;
bool st[N] ;
void insert(char s[]){
int p = 0 ;
for(int i = 1 ; s[i] ; i ++){
int x = s[i] - 'A' ;
if(!tr[p][x]) tr[p][x] = ++ idx ;
p = tr[p][x] ;
}
st[p] = 1 ;
}
void build(){
int hh = 0,tt = -1;
for(int i = 0 ; i < 26 ; i ++)
if(tr[0][i]) q[++tt] = tr[0][i] ;
while(hh <= tt){
int t = q[hh++] ;
for(int i = 0 ; i < 26; i ++){
int j = tr[t][i] ;
if(!j) tr[t][i] = tr[ne[t]][i] ;
else{
ne[j] = tr[ne[t]][i] ;
q[++tt] = j ;
}
}
}
for(int i = 0 ; i <= tt ; i ++) // 这里就是按照拓扑序进行向下递推
st[q[i]] |= st[ne[q[i]]] ;
}
}
int main(){
scanf("%d%d",&n,&m) ;
for(int i = 1 ; i <= n ; i ++){
scanf("%s",s+1) ;
Acam::insert(s) ;
}
Acam::build() ;
f[0][0] = 1 ;
int ans = 1 ;
for(int i = 1 ; i <= m ; i ++){
for(int pre = 0 ; pre <= Acam::idx ; pre ++) f[i&1][pre] = 0 ;
for(int pre = 0 ; pre <= Acam::idx ; pre ++){ // 枚举节点
if(Acam::st[pre]) continue ; // 这里会加快算法运行
for(int c = 0 ; c < 26 ; c ++){ // 枚举下一个选什么
int nx = Acam::tr[pre][c] ;
if(Acam::st[nx]) continue ;
f[i&1][nx] += f[i&1^1][pre] ; // 状态转移
if(f[i&1][nx] > mod) f[i&1][nx] -= mod ;
}
}
ans = ans * 26 % mod ;
}
for(int i = 0 ; i <= Acam::idx ; i ++) ans = (ans - f[m&1][i]) % mod ;
printf("%d\n",(ans + mod) % mod) ;
return 0 ;
}