[(http://acm.hdu.edu.cn/showproblem.php?pid=2243)]
我觉得很不错的一道AC自动机
首先把题目转换为求不含词根的数量
考虑构造一个矩阵mat[i][j]表示状态i到状态j走一步的数量
其中i和j必须要是合法状态
设s1=26^1+26^2+…+26^L,s2=mat^1+mat^2+…+mat^L
则答案等于s1-s2
mat可以由ac自动机辅助构造
注意s2的求法 可以看这个blog
[(http://www.cnblogs.com/ftae/p/7351524.html)]
#include<cstdio>
#include<cstring>
using namespace std;
typedef unsigned long long ULL;
int N;
char S[6];
int Tot,Son[30][26];
bool Can[30];
int Fail[30],Q[30];
ULL L,Mat[65][65],Tmp[65][65],Ans[65][65],Base[65][65];
void Insert(){
int i,u=0,l=strlen(S+1),c;
for(i=1;i<=l;i++){
c=S[i]-'a';
if(!Son[u][c])
Son[u][c]=++Tot;
u=Son[u][c];
}
Can[u]=false;
}
void Init(){
int i;
Tot=0;
memset(Son,0,sizeof(Son));
memset(Can,true,sizeof(Can));
for(i=1;i<=N;i++){
scanf("%s",S+1);
Insert();
}
}
void Get_Fail(){
int i,u,v,h=0,t=1,tmp;
memset(Fail,-1,sizeof(Fail));
Q[h]=0;
while(h<t){
u=Q[h++];
for(i=0;i<26;i++)
if(v=Son[u][i]){
tmp=Fail[u];
while(tmp!=-1&&!Son[tmp][i])
tmp=Fail[tmp];
Fail[v]=tmp==-1?0:Son[tmp][i];
Can[v]&=Can[Fail[v]];
Q[t++]=v;
}
else Son[u][i]=Fail[u]==-1?0:Son[Fail[u]][i];
}
}
void Get_Matrix(){
int i,j,tmp;
memset(Mat,0,sizeof(Mat));
for(i=0;i<=Tot;i++)
if(Can[i])
for(j=0;j<26;j++)
if(Can[tmp=Son[i][j]])
Mat[i][tmp]++;
for(i=0;i<=Tot;i++)
Mat[i][i+Tot+1]=1;
for(i=Tot+1;i<=2*Tot+1;i++)
Mat[i][i]=1;
}
void Mul(ULL a[65][65],ULL b[65][65],int l){
int i,j,k;
memset(Tmp,0,sizeof(Tmp));
for(i=0;i<l;i++)
for(j=0;j<l;j++)
for(k=0;k<l;k++)
Tmp[i][j]+=a[i][k]*b[k][j];
memcpy(a,Tmp,sizeof(Tmp));
}
void Pow(ULL base[65][65],ULL n,int l){
int i;
memset(Ans,0,sizeof(Ans));
for(i=0;i<l;i++)
Ans[i][i]=1;
while(n){
if(n&1)
Mul(Ans,base,l);
Mul(base,base,l);
n>>=1;
}
memcpy(base,Ans,sizeof(Ans));
}
void Work(){
int i;
ULL sum=0;
Pow(Mat,L+1,2*Tot+2);
for(i=Tot+1;i<=2*Tot+1;i++)
sum+=Mat[0][i];
Base[0][0]=Base[0][1]=26,Base[1][1]=1;
Pow(Base,L-1,2);
printf("%llu\n",(Base[0][1]+Base[1][1])*26-sum+1);
}
int main(){
while(~scanf("%d%llu",&N,&L)){
Init();
Get_Fail();
Get_Matrix();
Work();
}
return 0;
}