f[i][j]表示到第i个位置匹配自动机上第j个结点的方案数。
ans=所有排列-无单词的排列。
一开始我们可以在初始化确定哪些点不能作为最后一个点。在确定每一位的时候可以用自动机进行快速的查找。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define mod 10007
int siz,n,m,point[6010],a[6010][27],danger[6010],sum=1,tol;
int f[105][6010],q[mod];
char s[6100];
void ins()
{
int l=strlen(s),t,now=1;
for(int i=0;i<l;i++)
{
t=s[i]-'A'+1;
if(a[now][t]) now=a[now][t];
else {siz++;a[now][t]=siz;now=siz;};
}
danger[now]=1;
}
void acmach()
{
int head=0,tail=1;
point[0]=1;
q[1]=1;
int now,k;
while(head<tail)
{
head++;
now=q[head];
for(int i=1;i<=26;i++)
{
if(!a[now][i])
{
a[now][i]=a[point[now]][i];
continue;
}
k=point[now];
while(!a[k][i]) k=point[k];
point[a[now][i]]=a[k][i];
if(danger[a[k][i]])
danger[a[now][i]]=1;
tail++;
q[tail]=a[now][i];
}
}
}
void getf(int x)
{
for(int i=1;i<=siz;i++)
{
if(danger[i]||!f[x-1][i]) continue;
for(int j=1;j<=26;j++)
{
int k=i;
while(!a[k][j]) k=point[k];
f[x][a[k][j]]+=f[x-1][i];
f[x][a[k][j]]%=mod;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
siz=1;
for(int i=1;i<=26;i++) a[0][i]=1;
for(int i=1;i<=n;i++)
{
scanf("%s",s);
ins();
}
acmach();
f[0][1]=1;
for(int i=1;i<=m;i++) getf(i);
for(int i=1;i<=m;i++) sum=(sum*26)%mod;
for(int i=1;i<=siz;i++)
{
if(danger[i]) continue;
sum-=f[m][i];if(sum<0) sum+=mod;
}
printf("%d",sum%mod);
return 0;
}