题意:一只猴子可以有n个键 可以敲m下
求能敲出目标串的概率。
思路:可以先求不能敲出目标串的概率
用 dp[i][j] 表示 敲第 i 下时, 得到 目标串 j 结尾 的概率
例: 目标串 word
wcwor 这是dp[ 5 ][ 3 ] 的状态。。
如果目标串是 aaaaabaaaa 这样的
就会转移到奇怪的地方。。
所以先预处理出 每个状态转移的下个状态
然后很方便的算出来了。。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PI;
double p[123];
double dp[1200][20];
int to[12][134];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m),n+m)
{
memset(dp,0,sizeof(dp));
memset(p,0,sizeof(p));
for(int i=0;i<n;i++)
{
char x[3];
double y;
scanf("%s%lf",x,&y);
p[x[0]]=y;
}
char s[123],str[123],lenn=1;
memset(str,0,sizeof(str));
scanf("%s",s+1);
int len=strlen(s+1);
memset(to,-1,sizeof(to));
for(int i=1;i<=len;i++)//预处理 , str 为状态串
{
for(int j='a';j<='z';j++)
{
str[lenn]=j;//当前串能转移到哪里
for(int k=1;k<=lenn+1;k++)//得到 状态串 与 ( lenn长度 ) 的目标串的最大后缀长度
{
int flag=0;
for(int w=k,st=1;w<=lenn;w++,st++)
{
if(s[st]!=str[w])
flag=1;
}
//第i个位置加j字母的位置
if(flag==0)
{
to[i-1][j]=lenn-k+1;//下一个状态
// printf("%s %d\n",str+1,to[i][j]);
break;
}
}
}
str[lenn++]=s[i];
}
dp[0][0]=1;
for(int i=1;i<=m;i++)
{
for(int j=0;j<len;j++)
{
for(int k='a';k<='z';k++)
{
if(to[j][k]!=-1&&p[k]!=0)
{
dp[i][to[j][k]]+=dp[i-1][j]*p[k];
// cout<<i<<" "<<to[j][k]<<" "<<dp[i-1][j]*p[k]<<endl;
}
}
}
}
double ans=0;
for(int i=0;i<len;i++)
ans+=dp[m][i];
printf("%.2lf%%\n",100.0-ans*100);
}
return 0;
}