Infinite monkey theorem(hdu 3689)

题意:问随机生成一个长度为m(m<=1000)长度的字符串,出现某个子串s的概率是多少。

/*
  KMP+DP
  设f[i][j]表示A生成到第i位,此时B串匹配到第j位的概率。 
  转移方程为f[i+1][k]+=f[i][j]*lv(枚举的第i位生成字符的概率)
  k位如果第i位生成该字符,那么它能和B串匹配到的地方。 
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#define N 1010
using namespace std;
double lv[30],dp[N][N];
char s[N],zifu[30];
int n,m,len,fail[N];
void get_fail(){
    fail[1]=0;
    for(int i=2;i<=len;i++){
        int p=fail[i-1];
        while(p&&s[p+1]!=s[i]) p=fail[p];
        if(s[p+1]==s[i]) fail[i]=p+1;
        else fail[i]=0;
    }
}
void work(){
    for(int i=1;i<=n;i++){
        char c;cin>>zifu[i];
        scanf("%lf",&lv[i]);
    }
    scanf("%s",s+1);len=strlen(s+1);
    get_fail();
    dp[0][0]=100.0;
    for(int i=0;i<m;i++)
        for(int j=0;j<len;j++)
            for(int k=1;k<=n;k++){
                int p=j;
                while(p&&s[p+1]!=zifu[k])p=fail[p];
                if(s[p+1]==zifu[k])dp[i+1][p+1]+=dp[i][j]*lv[k];
                else dp[i+1][0]+=dp[i][j]*lv[k];
            }
    double ans=0;
    for(int i=1;i<=m;i++)ans+=dp[i][len];
    printf("%.2lf",ans);cout<<"%"<<endl;
}
int main(){
    while(scanf("%d%d",&n,&m)){
        if(!n&&!m)break;
        memset(fail,0,sizeof(fail));
        memset(dp,0,sizeof(dp));
        work();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/harden/p/6414266.html