【CodeForces908D】New Year and Arbitrary Arrangement (期望DP)

题目大意

有一个ab字符串,初始为空。
PaPa+Pb 的概率在末尾添加字母a,有 PbPa+Pb 的概率在末尾添加字母b,当出现≥k个ab子串时立即停止添加字母,求最后期望的ab子串个数。(子串ab不要求连续)
例子:当k=1,aab含2个ab,bbabbab时不可能出现的,因为到了bbab就会停止添加字母。

题解

dp[i][j]表示前缀包含i个a,j个ab子串的所有字符串,得到的期望ab子串个数。

转移:
在此前缀后添上a: dp[i][j]+=dp[i+1][j]×PaPa+Pb
在此前缀后添上b: dp[i][j]+=dp[i][j+i]×PbPa+Pb

初始状态: dp[i][j]=j (jk)
目标状态: dp[0][0] (无前缀,代表所有串)
但这两条↑是错的

还有一些无穷情况:

1.前缀出现了无穷多个b:bbbbb…….bbbbaababa…
显然在第一个a之前的所有b都没有任何用处,为了结束添加字母,则必定会出现a,所以目标状态一定会出现前缀有一个a,没有ab的情况,所以,目标状态应定义为 dp[1][0]

2.出现了无穷多个a:ababaaaa……..aaaaaab,虽然这样概率很小,但是把b添加在末尾,会增加一大堆ab,不可忽略,如果使用dp,会使i值增加到无穷大。
所以,将初始状态定义为 dp[i][j] (i+jk) ,然后通过数学计算:

pa=PaPa+Pb pb=PbPa+Pb S=dp[i][j]

S=(i+j)pb+pa(i+j+1)pb+p2a(i+j+2)pb+.......

paS=                     pa(i+j)pb+p2a(i+j+1)pb+.......

SpaS=(i+j)pb+(pa+p2a+p3a+...)pb

(1pa)S=(i+j)pb+pa(1pa)pb1pa

pbS=(i+j)pb+papbpb

S=i+j+papb

则初始状态
dp[i][j]=i+j+PaPb

代码

我用的记忆化搜索,方便理解

#include<cstdio>
#include<cstring>
const int MAXK=1005,MOD=1000000007;

int pow_mod(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=(1LL*res*a)%MOD;
        b>>=1;
        a=(1LL*a*a)%MOD;
    }
    return res;
}
int inv(int x)
{return pow_mod(x,MOD-2);}

int dp[MAXK][MAXK];
int k,pa,pb;

int DP(int i,int j)
{
    if(i+j>=k)
        return (i+j+1LL*pa*inv(pb)%MOD)%MOD;
    if(dp[i][j]!=-1)
        return dp[i][j];
    return dp[i][j]=(1LL*((1LL*pa*DP(i+1,j))%MOD+(1LL*pb*DP(i,i+j))%MOD)*inv(pa+pb))%MOD;
}

int main()
{
    scanf("%d%d%d",&k,&pa,&pb);
    memset(dp,-1,sizeof dp);
    printf("%d\n",DP(1,0));
    return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值