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

版权声明:本文为博主原创文章,请随意转载(注明出处)。若广告影响阅读,请安装Adblock Plus。 https://blog.csdn.net/can919/article/details/78940673

题目大意

有一个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+Pbpb=PbPa+PbS=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;
}
展开阅读全文

没有更多推荐了,返回首页