一、题目
二、解法
AC \text{AC} AC自动机上 d p dp dp,这里有一个加强版
设 f [ i ] [ j ] f[i][j] f[i][j]为长度为 i i i,匹配到了自动机上的点 j j j。 d p dp dp时直接暴力转移即可,注意当出现了一个认识的单词后立即算贡献,未填的随便选,停止它的转移。
时间复杂度 O ( 26 × 100 × n m ) O(26\times 100\times nm) O(26×100×nm),贴个代码。
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int M = 6005;
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,ans,f[105][M];
char s[M];
int qkpow(int a,int b)
{
int res=1,mod=10007;
while(b>0)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
struct Automaton
{
int c[M][26],val[M],fail[M],cnt;
void ins(char *s)
{
int len=strlen(s),now=0;
for(int i=0; i<len; i++)
{
int v=s[i]-'A';
if(!c[now][v]) c[now][v]=++cnt;
now=c[now][v];
}
val[now]=1;
}
void build()
{
queue<int> q;
for(int i=0; i<26; i++) if(c[0][i]) q.push(c[0][i]);
while(!q.empty())
{
int t=q.front();
q.pop();
for(int i=0; i<26; i++)
if(c[t][i])
{
fail[c[t][i]]=c[fail[t]][i];
if(val[fail[c[t][i]]]) val[c[t][i]]=1;
q.push(c[t][i]);
}
else c[t][i]=c[fail[t]][i];
}
}
void dp()
{
f[0][0]=1;
for(int i=0; i<=m; i++)
for(int j=0; j<=cnt; j++)
for(int k=0; k<26; k++)
{
if(val[j])
{
ans=(ans+f[i][j]*qkpow(26,m-i))%10007;
break;
}
f[i+1][c[j][k]]+=f[i][j];
f[i+1][c[j][k]]%=10007;
}
printf("%d\n",ans);
}
} AC;
int main()
{
n=read();
m=read();
for(int i=1; i<=n; i++)
{
scanf("%s",s);
AC.ins(s);
}
AC.build();
AC.dp();
}
//26*100*100*60