一开始以为期望好难啊QAQ
然后瞄了一下题解发现并不难? 1A 很舒服
建出自动机之后当然是用自动机节点来进行矩乘
算一下两点间转移概率什么的就好
为了统计答案 我们就弄多一个点 o=tot+1 设p=1/alphabet
转移到的点如果已经是终点了 就让他 连向o概率+=p 连向根的也+=p
然后a[o][o]=1来统计答案就好
还是不太懂就看代码吧~
我的代码简直就是好看啊2333
#include<bits/stdc++.h>
#define me(a,x) memset(a,x,sizeof a)
using namespace std;
const int N=105;
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
return x*f;
}
int t[N][26],fail[N],tot;
bool v[N],bo[N]; char s[20];
void ins(){
int x=0,len=strlen(s);
for(int i=0;i<len;++i){
int y=s[i]-'a';
if(!t[x][y])t[x][y]=++tot;
x=t[x][y];
}v[x]=1;
}
int Q[N],m,o;
void bulid(){
int he=0,ta=0;
while(he<=ta){
int x=Q[he++];
for(int i=0;i<m;++i){
int u=t[x][i],f=fail[x];
if(!u){t[x][i]=t[f][i]; continue;}
if(x)fail[u]=t[f][i]; else fail[u]=0;
v[u]|=v[fail[u]],Q[++ta]=u;
}
}
}
struct mat{
long double a[N][N];
mat(){me(a,0);}
}a,ans;
inline mat operator*(mat &x,mat &y){
mat z;
for(int i=0;i<=o;++i)for(int j=0;j<=o;++j)for(int k=0;k<=o;++k)
z.a[i][j]+=x.a[i][k]*y.a[k][j];
return z;
}
void pre(){
int he=0,ta=0; bo[0]=1; long double p=1.0/m;
while(he<=ta){
int x=Q[he++];
for(int i=0;i<m;++i){
int u=t[x][i];
if(!bo[u])bo[u]=1,Q[++ta]=u;
if(v[u])a.a[x][o]+=p,a.a[x][0]+=p;
else a.a[x][u]+=p;
}
}
}
int main(){
int n=read(),k=read(); m=read();
for(int i=0;i<n;++i)scanf("%s",s),ins();
bulid(); o=tot+1; pre();
a.a[o][o]=1;
for(int i=0;i<=o;++i) ans.a[i][i]=1;
for(;k;k>>=1,a=a*a) if(k&1) ans=ans*a;
printf("%.7lf\n",(double)ans.a[0][o]);
return 0;
}