HDU 3689 KMP+DP
题意为一只猴子随机输入字符串,每个字母的概率已经给出。
求猴子输入长度为N的字符串S1包含模式串S2的概率。
很有趣的KMP题目,在Matrix67博客里看过类似的文章,一下子就想起来了。
http://www.matrix67.com/blog/archives/366
博客里应该说的很明白了。一个利用next数组进行dp的过程。
dp[i][j]表示输入第i个字符模式串匹配到第j个字符的概率。
然后从上往下dp。。O(n)的状态转移
对于每个状态,枚举下一个输入的字符c,设概率为p
kmp中,母串每后移一个字符,模式串指针的位置仅由新字符决定。
可以根据kmp匹配过程计算出新的j的值。设为j2
则dp[i+1][j2]+=dp[i][j]*p;
最后的答案为 ans=dp[1..n][j]
即任意位置得母串匹配到模式串结束位置的概率和。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAXN = 30; char s[MAXN]; int F[MAXN]; int M,N,L; char c[MAXN]; double p[MAXN]; void callnext(){ F[1]=0; int j=0; for (int i=2;i<=L;i++){ while(j && s[j+1]!=s[i]) j=F[j]; if (s[j+1]==s[i]) j++; F[i]=j; } } double dp[1010][MAXN]; int main(){ freopen("in.txt","r",stdin); while(1){ memset(dp,0,sizeof(dp)); scanf("%d%d\n",&M,&N); if (!M&&!N) break; for (int i=1;i<=M;i++) scanf("%c %lf\n",&c[i],&p[i]); scanf("%s",s+1); L = strlen(s+1); callnext(); dp[0][0]=1; for (int i=0;i<N;i++) for (int j=0;j<L;j++) for (int k=1;k<=M;k++){ int po=j; while(po&&s[po+1]!=c[k]) po=F[po]; if (s[po+1]==c[k]) po++; dp[i+1][po]+=dp[i][j]*p[k]; } double ans=0; for (int i=0;i<=N;i++) ans+=dp[i][L]; printf("%.2lf%%\n",ans*100); } }