Description
給定 \(k,pa,pb\),有一初始為空的序列。
每次有 \(\dfrac{pa}{pa+pb}\) 的機率往序列後面加一個 a
。
每次有 \(\dfrac{pb}{pa+pb}\) 的機率往序列後面加一個 b
。
當出現大於等於 \(k\) 個形如 ab
的子序列(a
和 b
不一定相鄰)時停止。
求序列最終的 ab
子序列期望數。
Solution
為了更加簡潔,文中的 \(pa\) 指題意中的 \(\dfrac{pa}{pa+pb}\),\(pb\) 指 \(\dfrac{pb}{pa+pb}\)。
看到求期望,可以先試著寫寫 dp
。
設 \(f_{i,j,t}\) 表示有 \(i\) 個 a
、\(j\) 個 b
、\(t\) 個 ab
時的期望。
發現當前有 \(i\) 個 a
時,再加一個 b
會產生 \(i\) 個 ab
,與之前 b
的數量無關,所以省去一維 dp
。
設 \(f_{i,j}\) 表示有 \(i\) 個 a
、\(j\) 個 ab
時的期望。
由於我們只知道終止狀態,所以倒推會更好寫且容易理解。
\(f_{i,j}\) 有 \(pa\) 的機率加 a
變為 \(f_{i+1,j}\),有 \(pb\) 的機率加 b
變為 \(f_{i,j+i}\),得出轉移方程:
答案即為 \(f_{1,0}\)。
接下來是本題最難部分,求滿足終止條件的 \(f\) 值。
終止條件為 \(i+j\ge k\),此時只要再加一個 b
就可以終止。
然而在加 b
前可能有若干個 a
,無法確定 a
的數量,所以要開始推式子。
Sol1
這種方法用了等比數列的思想。
\(x\) 為 a
的出現次數,a
每多在 b
前出現一次,最後的 ab
就會多一個,所以總共加了 \(i+j+x\) 個 ab
。
繼續推:
設 \(T=\sum\limits_{x=0}^\infty pa^x\times x\)。
\(x\) 變為 \(x-1\) 的原因是 \(x\) 變為 \(1\) 開始。
設 \(S=\sum\limits_{x=0}^\infty pa^x\)。
Sol2
對於 \(f_{i,j}\) 和 \(f_{i+1,j}\)(\(i+j\ge k\)):
由於後面的 b
終止前,新的 a
產生的多餘 ab
期望數都是一樣的。
所以兩期望的區別只有當前 a
相差 \(1\) 造成的期望 \(1\)。
即 \(f_{i+1,j}=f_{i,j}+1\)。
Code
#include<bits/stdc++.h>
using namespace std;
#define mo 1000000007
#define int long long
int k,a,b,pa,pb;
int f[1010][1010];
int po(int x,int y){
int z=1;
while(y){
if(y%2) z*=x;
x*=x;
x%=mo,z%=mo;
y/=2;
}
return z;
}
signed main(){
cin>>k>>a>>b;
pa=a*po(a+b,mo-2)%mo;
pb=b*po(a+b,mo-2)%mo;
for(int i=k;i>=1;i--){
for(int j=k;j>=0;j--){
if(i+j>=k){
f[i][j]=pa*po(pb,mo-2)%mo+i+j;
f[i][j]%=mo;
}else{
f[i][j]=f[i+1][j]*pa%mo+f[i][j+i]*pb%mo;
f[i][j]%=mo;
}
}
}
cout<<f[1][0];
return 0;
}