Solution
f[i][j]表示前 i个字符,在 trie树上 j的位置的期望
对于 u及其儿子 v,若v是危险节点,那么 u到 0连边,否则 u到 v连边
因为统计的是 0到 n的所有不同长度的期望值之和,所以还要加个虚拟节点,记录答案
Code
#include<bits/stdc++.h>
using namespace std;
typedef long double ld;
int q[77],n,len,sum,tr[77][26],m,fail[77],i;
char s[17];
bool vis[77],fl[77];
struct M{
ld a[77][77];
friend M operator *(M x,M y){
M z;memset(z.a,0,sizeof(z.a));
for (int i=0;i<=n;i++)
for (int j=0;j<=n;j++)
for (int k=0;k<=n;k++) z.a[i][j]+=x.a[i][k]*y.a[k][j];
return z;
}
friend M operator ^(M x,int y){
M z;memset(z.a,0,sizeof(z.a));
for (int i=0;i<=n;i++) z.a[i][i]=1;
for (;y;y>>=1,x=x*x)
if (y&1) z=z*x;
return z;
}
}f;
void ins(char *s){
int k=0;
for (int i=0;s[i];i++){
int &son=tr[k][s[i]-'a'];
if (!son) son=++sum;
k=son;
}
fl[k]=1;
}
void build(){
int h=0,t=1;
while (h<t){
int u=q[h++];
for (int i=0;i<m;i++){
int &v=tr[u][i];
if (v){
if (u) fail[v]=tr[fail[u]][i];
q[t++]=v;
}else v=tr[fail[u]][i];
}
fl[u]|=fl[fail[u]];
}
}
void make(){
int h=0,t=1;
ld tmp=(ld)1/m;
vis[0]=1;
while (h<t){
int u=q[h++];
for (int i=0;i<m;i++){
int v=tr[u][i];
if (!vis[v]) vis[v]=1,q[t++]=v;
if (fl[v]) f.a[u][0]+=tmp,f.a[u][n]+=tmp;
else f.a[u][v]+=tmp;
}
}
f.a[n][n]=1;
}
int main(){
scanf("%d%d%d",&n,&len,&m);
for (i=0;i<n;i++) scanf("%s",s),ins(s);
n=sum+1;
build(),make();
printf("%.7Lf",(f^len).a[0][n]);
}