hdu-3689 Infinite monkey theorem 概率dp+kmp
有一只猴子随机敲键盘,给出它可能敲的键以及敲各个键的概率。
输入:n,表示有多少个键,m,表示猴子会敲m次键
n个二元组(字母,数字)
表示键代表的字母及其被敲的概率。
最后一个目标字符串。
问这只猴子敲了m次键后得到的字符串包含目标字符串的概率。
最主要的还是怎么定义出具有无后效性的状态。
用dp[i][j]表示扫描第i位,前面未曾出现完全匹配并且后缀与target已匹配长度为j的概率
然后模仿kmp匹配的过程进行dp就可以了。
AC代码:
#include<bits/stdc++.h> using namespace std; const int MAXN=30; const int MAXLEN=1010; int n,m; double p[MAXN]; char target[20]; double dp[MAXLEN][20]; //dp[i][j]表示扫描第i位,前面未曾出现完全匹配&&后缀与target已匹配长度为j的概率 int nxt[20]; double ans; void init() { for(int i=0;i<MAXN;++i) p[i]=0.0; ans=0; for(int i=0;i<=m;++i) { for(int j=0;j<20;++j) { dp[i][j]=0.0; } } dp[0][0]=1.0; } void Input() { char c,t; for(int i=1;i<=n;++i) { scanf("%c%c",&t,&c); cin>>p[c-'a']; } scanf("%s",target); } void getnxt(char P[]) { nxt[0]=0; int len=strlen(P),k=0; for(int i=1;i<len;++i) { while(k&&P[i]!=P[k]) k=nxt[k-1]; if(P[i]==P[k]) ++k; nxt[i]=k; } } void work() { int len=strlen(target); getnxt(target); for(int i=1;i<=m;++i) { for(int k=0;k<26;++k) { for(int j=1;j<=len;++j) { int now=j-1; while(now&&target[now]!=k+'a') now=nxt[now-1]; if(target[now]==k+'a') { dp[i][now+1]+=dp[i-1][j-1]*p[k]; } else dp[i][0]+=dp[i-1][j-1]*p[k]; } } ans+=dp[i][len]; } } int main() { while(scanf("%d%d",&n,&m)==2&&(n+m)) { init(); Input(); work(); printf("%.2f%%\n",100*ans); } return 0; }