CF 908 D New Year and Arbitrary Arrangement —— 期望DP

题目:http://codeforces.com/contest/908/problem/D

首先,设 f[i][j] 表示有 i 个 a,j 个 ab 组合的期望,A = pa / (pa + pb) , B = pb / (pa + pb)

那么 f[i][j] = A * f[i+1][j] + B * f[i][i+j]

当 i+j >= k 时,再出现一个 b 就会结束,所以此时:

f[i][j] = f[i][i+j] * B + f[i+1][i+j+1] * A * B + f[i+2][i+j+2] * A2 * B + ... + f[i+∞][i+j+∞] * A * B

化简一番(等比数列求和,1 - A = B)得到 f[i][j] = i + j + A / B

于是就可以做了;

不会刷表就记忆化搜索...

注意取的答案是 dp(1,0) 而非 dp(0,0),因为 dp(0,0) 会一直调用自己,而 dp(1,0) 可以看做是从第一个 a 出现开始算,反正前面没有 a ,对答案无影响。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=1005,mod=1e9+7;
int k,a,b,c,f[maxn*2][2*maxn];
bool vis[maxn][maxn];
int pw(int a,int b)
{
    int ret=1;
    for(;b;b>>=1,a=((ll)a*a)%mod)
        if(b&1)ret=((ll)ret*a)%mod;
    return ret;
}
int dp(int i,int j)
{
    if(vis[i][j])return f[i][j];
    vis[i][j]=1;
    if(i+j>=k)return f[i][j]=(i+j+c)%mod;
    f[i][j]=((ll)a*dp(i+1,j)+(ll)b*dp(i,i+j))%mod;
    return f[i][j];
}
int main()
{
    int pa,pb;
    scanf("%d%d%d",&k,&pa,&pb);
    int tmp=pw(pa+pb,mod-2);
    a=(ll)pa*tmp%mod; b=(ll)pb*tmp%mod;
    c=(ll)a*pw(b,mod-2)%mod;
//    for(int i=0;i<=2*k;i++)
//        for(int j=max(k-i,0);j<=2*k;j++)
//            f[i][j]=f[j][i]=(i+j+c)%mod;
    // for(int i=k;i>=0;i--)
//        for(int j=k;j>=0;j--)
//            f[i][j]=(a*f[i+1][j]+b*f[i][i+j])%mod;
    printf("%d\n",dp(1,0));//0,0 会调用自己
    //如果不是从第一个a算起,前面一堆b没用
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/9676741.html

时间: 2024-08-01 17:03:47

CF 908 D New Year and Arbitrary Arrangement —— 期望DP的相关文章

Codeforces 908 D.New Year and Arbitrary Arrangement (概率&amp;期望DP)

题目链接:New Year and Arbitrary Arrangement 题意: 有一个ab字符串,初始为空. 用Pa/(Pa+Pb)的概率在末尾添加字母a,有 Pb/(Pa+Pb)的概率在末尾添加字母b,当出现≥k个ab子串时立即停止添加字母,求最后期望的ab子串个数.(子串ab不要求连续) 例子:当k=1,aab含2个ab,bbabbab时不可能出现的,因为到了bbab就会停止添加字母. 题解: 期望DP DP果然是智商的分界线 orz @.@#,这题题意其实我也没看太懂,后来看了别人

Codeforces 908 D New Year and Arbitrary Arrangement

Discription You are given three integers k, pa and pb. You will construct a sequence with the following algorithm: Initially, start with the empty sequence. Each second, you do the following. With probability pa?/?(pa?+?pb), add 'a' to the end of the

Codeforces 908D New Year and Arbitrary Arrangement(概率DP,边界条件处理)

题目链接  Goodbye 2017 Problem D 题意  一个字符串开始,每次有$\frac{pa}{pa+pb}$的概率在后面加一个a,$\frac{pb}{pa+pb}$的概率在后面加一个$b$. 求当整个串中有至少$k$个$ab$的时候(不需要连续,下同),字符串中$ab$个数的期望. 设$f[i][j]$为字符串有$i$个$a$,$j$个$ab$的时候字符串中$ab$个数的期望 设$p = \frac{pa}{pa+pb}$, $q = \frac{pb}{pa+pb}$ 那么对

【CF908D】New Year and Arbitrary Arrangement

Problem Description 给定三个数 \(k,pa,pb\) ,每次有 \(\frac{pa}{pa+pb}\) 的概率往后面添加一个 a,有 \(\frac{pb}{pa+pb}\) 的概率往后面添加一个 b ,当出现了 \(k\) 个形如 ab 的子序列(不用连续)时停止. 求最后子序列 ab 的期望个数. 答案对 \(10^9+7\) 取模. Sample Input 1 1 1 1 Output 1 2 Input 2 3 1 4 Output 2 370000006 Ra

CF 713C Sonya and Problem Wihtout a Legend(DP)

原版题意:给定一个序列,每次操作给其中一个数$+1$或$-1$,问最少需要多少操作使得整个序列为不下降序列. 题解:不下降序列最后修改完成后的各个数一定是原序列中的某一个数.关于这个的理解看到网上的一个解释:原序列,从左到右扫过去,如果左边的大于右边的,要么左边的减掉使其等于右边的,要么右边的加上使其等于左边的. $dp[i][j]$:前i个数以原序列排序后的第j个数为结尾需要的最少操作. 状态转移方程:$dp[i][j]=min(dp[i][j-1],dp[i-1][j]+abs(a[i]-b

Educational CF # 17 C 二分,字符串 D 最长路,dp

Educational Codeforces Round 17 C. Two strings 题意:两个字符串A,B,从B中删除尽可能少的子串,要使得B剩下的字符串是A的子序列,输出B剩下的字符串.(注意子串与子序列区别) 总结:看了某神犇的代码,不太理解..官方题解:不要去想从B中删掉子串,应该想,从B的左端取出一段子串,再从右端取出一段子串. // Educational Codeforces Round 17 C #include<bits/stdc++.h> using namespa

CF#301 D:Bad Luck Island (概率dp)

D:Bad Luck Island 一个岛上有r个石头,s个剪子,p个布,他们之间随机挑出两个相遇,如果不是相同物种,就会有一个消失,分别求出最后这座岛上只剩下一个物种的概率. 我们用dp[i][j][k]来存储剩下 i 个石头, j 个剪刀,k 个布时的概率,共dp三次: 如果石头与剪刀碰面,概率是 p1 = i*j / (i*j+j*k+k*i),这种情况下,剪刀会被石头吃掉,所以石头的数目减少1,表现出来是dp[i-1][j][k] = p1*dp[i][j][k]  (dp的3的返回值均

cf 398B. Painting The Wall【期望dp】

传送门:http://codeforces.com/problemset/problem/398/B Description: User ainta decided to paint a wall. The wall consists of n2 tiles, that are arranged in an n?×?n table. Some tiles are painted, and the others are not. As he wants to paint it beautifull

CF - 1106 E Lunar New Year and Red Envelopes DP

题目传送门 题解: 首先要处理出每个时间点会选择哪一个线段. 对于这个问题,可以用multiset去维护信息. 当时间线开始的时候,往mutiset里面插入这个信息,当时间线结束的时候,删除这个信息. 每次只要取出最大位就好了. 然后,就是状态转移,注意的就是只有转移进来过的状态才能转移出去. 代码: /* code by: zstu wxk time: 2019/02/03 */ #include<bits/stdc++.h> using namespace std; #define Fop