Infinite monkey theorem

7 篇文章 0 订阅
2 篇文章 0 订阅

来源: HDU 3689

题意

键盘上有n(<=1000)个按键,每个按键都有被敲到的概率。有一只会打字的monkey,求问它敲了m次后,最终串包含s(len<=10)的概率

分析

看起来n和s的len都小小的。
然后这里要求包含s即可。
状态也很好定义dp[i][j] 表示已经敲了i下,正在匹配第j位。
这里需要注意的是,当匹配到j不成功之后不一定都会回到匹配到1的情况。这种情况可以通过KMP来维护直接往前移即可。

据称暴力DP可过,但是感觉写起来应该也不会比KMP简单很多。

#include<cstdio>
#include<cstring>
#include<iostream>
#define db double
using namespace std;
db a[128],dp[1005][15];
int len,n,m,f[20];
char s[15],c;
bool t[128];

int main(){
//  freopen("3689.in","r",stdin);
    scanf("%d%d",&n,&m);
    for (; n!=0&&m!=0; ){
        int i,j,k,l; db p;
        memset(a,0,sizeof(a));
        memset(dp,0,sizeof(dp));
        memset(t,0,sizeof(t));
        memset(f,0,sizeof(f));
        for (i=1; i<=n; i++){
            for (c=getchar(); c<'a'||c>'z'; c=getchar());
            scanf("%lf",&p);
            a[c]=p; t[c]=1;
        }
        scanf("%s",s+1); len=strlen(s+1);
//      cout<<s<<endl;
        f[1]=0; f[2]=1; j=0;
        for (i=2; i<=len; i++){
            j++;
            for (; j&&s[i]!=s[j]; )j=f[j];
            f[i+1]=j+1;
        }       
        dp[0][1]=1.0;
        for (i=1; i<=m; i++){
            dp[i][len+1]=dp[i-1][len+1];
            for(k=1; k<=len; k++){
                for (j='a'; j<='z'; j++)if (t[j]){
                    l=k;
                    for (; l&&(s[l]!=j); )l=f[l];
                    l++; 
                    dp[i][l]+=dp[i-1][k]*a[j];
                }
            }
//          for (k=0; k<=len+1; k++)printf("%.5f ",dp[i][k]); printf("\n");
//          printf("\n");
        }
        printf("%.2f",100.0*dp[m][len+1]); puts("%");       
        scanf("%d%d",&n,&m);
    }   
    return 0;
}

一点提醒自己的

事实上忘了KMP怎么写了…然后这个地方还要复习。虽然似乎联赛并不会考到。暴力匹配也是没问题的。也就是 mnstrlen(s)2 (大概就是这个复杂度)
转移很好想,但是一开始没有考虑到失配之后不一定马上回到0导致对着数据发呆了很久。
这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值