题意:
给你n个串,求长度为l的串包含n个串个数的期望。
思路:
自动机dp[i][j][k] 长度为i在节点j状态为k的概率。
然后遍历一遍求期望。
代码:
#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
#include"map"
#include"stack"
#define N 123
#define eps 1e-8
using namespace std;
double dp[20][N][277];
int n,len;
struct Trie
{
int next[N][27],fail[N],mark[N];
int root,L;
int newnode()
{
memset(next[L],-1,sizeof(next[L]));
mark[L]=0;
fail[L++]=-1;
return L-1;
}
void go()
{
L=0;
root=newnode();
}
void init(char *v,int id)
{
int p=root;
for(int i=0; v[i]; i++)
{
int tep=v[i]-'a';
if(next[p][tep]==-1) next[p][tep]=newnode();
p=next[p][tep];
}
mark[p]|=(1<<id);
}
void build()
{
queue<int>q;
q.push(root);
while(!q.empty())
{
int p=q.front();
q.pop();
for(int i=0; i<26; i++)
{
if(next[p][i]==-1)
{
if(p==root) next[p][i]=root;
else next[p][i]=next[fail[p]][i];
}
else
{
if(p==root) fail[next[p][i]]=root;
else fail[next[p][i]]=next[fail[p]][i];
q.push(next[p][i]);
if(p!=root) mark[next[p][i]]|=mark[next[fail[p]][i]];
}
}
}
}
void solve()
{
memset(dp,0,sizeof(dp));
dp[0][0][0]=1.0;
for(int i=1; i<=len; i++)
{
for(int j=0; j<L; j++)
{
for(int k=0; k<(1<<n); k++)
{
for(int o=0; o<26; o++)
{
int tep=next[j][o];
dp[i][tep][mark[tep]|k]+=1.0/26*dp[i-1][j][k];
}
}
}
}
double ans=0;
for(int i=0; i<L; i++)
{
for(int j=1; j<(1<<n); j++)
{
int cnt=0;
for(int k=0; k<n; k++) if(j&(1<<k)) cnt++;
ans+=cnt*dp[len][i][j];
}
}
printf("%.6f\n",ans);
}
} ac;
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%d%d",&n,&len);
ac.go();
for(int i=0; i<n; i++)
{
char x[123];
scanf("%s",x);
ac.init(x,i);
}
ac.build();
ac.solve();
}
return 0;
}