1. 程式人生 > >CF 908 D New Year and Arbitrary Arrangement —— 期望DP

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

std con iostream algo print \n problem 就會 algorithm

題目: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; }

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