题意:
给你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; }
时间: 2024-09-27 23:26:48