题目大意:一群猴子打字,给定猴子输入每种字符的概率以及输入次数,求输出的文本中出现指定字符串的概率
强烈建议看这篇文章:http://www.matrix67.com/blog/archives/366 里面对这道题的分析很详细
思路比较清奇,我们先用KMP求出指定串的next,接下来是DP的过程
表示输入了i个字符,匹配到了第j个的概率
这道题是一个贪心的思路,我们在第j位可以填上任意字符,而如果第j位填上的字符不符合原串,即在当前第j位匹配失败,我们要从j-1的位置不断向前跳next(保证前缀都相同),直到匹配成功或者整个串的无法匹配,然后我们乘上该字符出现的概率即可。
for(int i=1;i<=m;i++)
{
for(int j=1;j<=len;j++)
{
for(int k=1;k<=26;k++)
{
int p=j-1;
while(p!=-1&&idx(t[p])!=k) p=nxt[p];
f[i][p+1] += f[i-1][j-1]*c[k];
}
}
}
核心代码段,认真思考理解一下
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define N 1010
#define M 30
#define L 12
#define mod 1000000007
#define ui unsigned int
#define ll long long
#define dd double
#define idx(x) x-'a'+1
using namespace std;
int T,n,m,len;
int nxt[L];
dd f[N][L],c[M];
char t[L];
void get_kmp()
{
int i=0,j=-1;
nxt[0]=-1;
while(i<len)
{
if(j==-1||t[i]==t[j])
{
i++;
j++;
nxt[i]=j;
}else{
j=nxt[j];
}
}
}
dd solve()
{
f[0][0]=1;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=len;j++)
{
for(int k=1;k<=26;k++)
{
int p=j-1;
while(p!=-1&&idx(t[p])!=k) p=nxt[p];
f[i][p+1] += f[i-1][j-1]*c[k];
}
}
}
dd ans=0;
for(int i=1;i<=m;i++) ans+=f[i][len];
return ans*(dd)100;
}
int main()
{
//freopen("aa.in","r",stdin);
while(1)
{
memset(f,0,sizeof(f));
memset(c,0,sizeof(c));
memset(nxt,0,sizeof(nxt));
scanf("%d%d",&n,&m);
if(n==0&&m==0) break;
for(int i=1;i<=n;i++)
{
scanf("%s",t);
scanf("%lf",&c[idx(t[0])]);
}
memset(t,0,sizeof(t));
scanf("%s",t);
len=strlen(t);
get_kmp();
printf("%.2lf",solve());
putchar('%');
puts("");
}
return 0;
}