题目描述
给定三个数k,pa,pb
每次有
p
a
p
a
+
p
b
\frac{pa}{pa+pb}
pa+pbpa 的概率往后面添加一个
a
a
a
每次有 p b p a + p b \frac{pb}{pa+pb} pa+pbpb 的概率往后面添加一个 b b b
当出现了K个形如ab的子序列(不用连续)时停止
求最后子序列 ab 个数的期望
Sol
首先我们假设有长度限制,设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示第到 i i i个字符已经有了 j j j个 a a a和 k k k个 a b ab ab的到最后停止的期望答案
最后答案即为
f
[
0
]
[
0
]
[
0
]
f[0][0][0]
f[0][0][0]
假设加a和b的概率就是 pa 和 pb
转移:
f
[
i
]
[
j
]
[
k
]
=
p
a
∗
f
[
i
+
1
]
[
j
+
1
]
[
k
]
+
p
b
∗
f
[
i
+
1
]
[
j
]
[
j
+
k
]
f[i][j][k]=pa*f[i+1][j+1][k]+pb*f[i+1][j][j+k]
f[i][j][k]=pa∗f[i+1][j+1][k]+pb∗f[i+1][j][j+k]
当
j
+
k
j+k
j+k大于
K
K
K 的时候后面一部分可以直接统计答案了
但是如果没有串长限制这样下去就没完没了了 , 主要不好处理的是一下两种情况:
- 一直放 b , 这样就无限转移了
- 一直放 a , 这样也没完没了
对于情况1 , 我们可以先强制放一个 a 这样其实一开始就会有 pa 的概率
然后由于前面的 b 不影响期望的权值 , 因此我们可在计算完答案后再来考虑
对于情况 2 , 我们发现如果 j + k j+k j+k 已经大于 K 了的话,那么放一个 b 就会停止
可以把式子不断递归化下去 , 根据我们的极限知识和无穷递减等比数列求和公式,最后式子变成了这个(注意这时i没有意义了,由于是倒推,做到了不重不漏):
f [ j ] [ k ] = ( i + j ) + p a p b f[j][k]=(i+j)+\frac{pa}{pb} f[j][k]=(i+j)+pbpa
这样就可以算了
在回到开头一段有一堆 b 的情况 , 假设我们强制第一个是 a 的期望是 E E E,那么最后的答案 E a n s = p a ∗ E + p b ∗ p a ∗ E + p b 2 ∗ p a ∗ E + . . . . . . . E_{ans}=pa*E+pb*pa*E+pb^2*pa*E+....... Eans=pa∗E+pb∗pa∗E+pb2∗pa∗E+.......
继续递降无穷等比数列求和:
E
a
n
s
=
E
E_{ans}= E
Eans=E
所以不要管开头的 b
(应该也可以通过期望的线性性来理解)
代码:
#include<bits/stdc++.h>
using namespace std;
int k,pa,pb;
const int mod=1e9+7;
const int N=1001;
inline int fpow(int x,int k)
{
register int res=1;
while(k){
if(k&1) res=1ll*res*x%mod;
x=1ll*x*x%mod;k>>=1;
}
return res;
}
int f[N][N];
int D;
int dfs(int i,int j)
{
if(i+j>=k) return f[i][j]=(i+j+D)%mod;
if(f[i][j]!=0) return f[i][j];
f[i][j]=1ll*pa*dfs(i+1,j)%mod+1ll*pb*dfs(i,i+j)%mod;
f[i][j]%=mod;
return f[i][j];
}
int main()
{
scanf("%d %d %d",&k,&pa,&pb);
register int inv=fpow(pa+pb,mod-2);
pa=1ll*pa*inv%mod;pb=1ll*pb*inv%mod;
D=1ll*pa*fpow(pb,mod-2)%mod;
dfs(1,0);
printf("%lld\n",1ll*f[1][0]%mod);
}