给出正整数p a , p b , k p_a,p_b,k p a , p b , k
一开始有一个空串,每一次有p a p a + p b \frac{p_a}{p_a+p_b} p a + p b p a 的概率在末尾加入a a a ,p b p a + p b \frac{p_b}{p_a+p_b} p a + p b p b 的概率在串末尾加入b b b
当串中存在k k k 个子序列a b ab a b 时停止,求停止时子序列a b ab a b 个数的期望,答案对1 0 9 + 7 10^9+7 1 0 9 + 7 取模
k ≤ 1 0 0 0 k \le 1000 k ≤ 1 0 0 0
Links CF908D
Solution
注:以下所有的p a p_a p a 表示原题中的p a p a + p b \frac{p_a}{p_a+p_b} p a + p b p a ,p b p_b p b 表示 p b p a + p b \frac{p_b}{p_a+p_b} p a + p b p b
显然子序列a b ab a b 的个数只与当前已经有多少个a a a 和已经出现的子序列a b ab a b 的个数有关
那么首先有一个很简单的dp:d p [ i ] [ j ] dp[i][j] d p [ i ] [ j ] 表示已经出现了i i i 个a a a ,j j j 个子序列a b ab a b ,到结束时子序列a b ab a b 个数的期望。
考虑往后加的是a a a 还是b b b ,很容易得到转移方程:
d p [ i ] [ j ] = d p [ i + 1 ] [ j ] ∗ p a + d p [ i ] [ i + j ] ∗ p b
dp[i][j] = dp[i + 1][j] * p_a + dp[i][i + j] * p_b
d p [ i ] [ j ] = d p [ i + 1 ] [ j ] ∗ p a + d p [ i ] [ i + j ] ∗ p b 但是我们会发现终止状态,也就是边界情况并不好处理,因为这个dp会无限进行下去
仔细思考一下,使得它无限进行下去的原因是这样一种情况:到后面a a a 的个数很多但b b b 很少,可能加上一个b b b 就会停止了,但一直加的是a a a
再提炼一下,发现就是当i + j ≥ k i+j\ge k i + j ≥ k 时很不好考虑
因此我们对于i + j ≥ k i+j\ge k i + j ≥ k 时,直接计算d p dp d p 值,因为此时只要再添一个b b b 就能终止
设S = d p [ i ] [ j ] ( i + j ≥ k ) S = dp[i][j](i+j\ge k) S = d p [ i ] [ j ] ( i + j ≥ k ) ,考虑这个b b b 什么时候被添上,那么就有:
S = ( i + j ) p b + ( i + j + 1 ) p a p b + ( i + j + 2 ) p a 2 p b + . . . = p b ∑ x = 0 ∞ ( i + j + x ) p a x
\begin{aligned}
S &= (i + j)p_b + (i + j + 1)p_ap_b + (i+j+2)p_a^2p_b+...\\\\
&=p_b\sum_{x=0}^{\infty}(i+j+x)p_a^x
\end{aligned}
S = ( i + j ) p b + ( i + j + 1 ) p a p b + ( i + j + 2 ) p a 2 p b + . . . = p b x = 0 ∑ ∞ ( i + j + x ) p a x 等比数列求和一下得到
S = i + j + ∑ x = 1 ∞ p a x
S = i + j + \sum_{x = 1}^{\infty}p_a^x
S = i + j + x = 1 ∑ ∞ p a x 其中∑ x = 1 ∞ p a x \sum_{x=1}^{\infty}p_a^x ∑ x = 1 ∞ p a x 就j是无穷等比数列求和,不难发现它就是p a ∞ − p a 1 − p a = p a p a − 1 = p a p b \frac{p_a^{\infty} - p_a}{1 - p_a} = \frac{p_a}{p_a - 1} = \frac{p_a}{p_b} 1 − p a p a ∞ − p a = p a − 1 p a = p b p a
所以当i + j ≥ k i+j\ge k i + j ≥ k 时,d p [ i ] [ j ] = i + j + p a p b dp[i][j] = i + j + \frac{p_a}{p_b} d p [ i ] [ j ] = i + j + p b p a
Summary 在dp边界是∞ \infty ∞ 时可以考虑把后面的某些dp值根据其具体意义直接计算
Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 #include <bits/stdc++.h> #define x first #define y second #define y1 Y1 #define y2 Y2 #define mp make_pair #define pb push_back using namespace std ;typedef long long LL;typedef pair <int , int > pii;template <typename T> inline int Chkmax (T &a, T b) { return a < b ? a = b, 1 : 0 ; }template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0 ; }template <typename T> inline T read () { T sum = 0 , fl = 1 ; char ch = getchar(); for (; !isdigit (ch); ch = getchar()) if (ch == '-' ) fl = -1 ; for (; isdigit (ch); ch = getchar()) sum = (sum << 3 ) + (sum << 1 ) + ch - '0' ; return sum * fl; } inline void proc_status () { ifstream t ("/proc/self/status" ) ; cerr << string (istreambuf_iterator <char > (t), istreambuf_iterator <char > ()) << endl ; } const int Maxn = 1e3 + 100 , Mod = 1e9 + 7 ;int Pa, Pb, K, Div;inline int Pow (int a, int b) { int ans = 1 ; for (int i = b; i; i >>= 1 , a = (LL)a * a % Mod) if (i & 1 ) ans = (LL)ans * a % Mod; return ans; } int Dp[Maxn][Maxn];inline int get_dp (int i, int j) { if (i + j >= K) return (i + j + Div) % Mod; if (Dp[i][j]) return Dp[i][j]; return Dp[i][j] = ((LL)get_dp (i + 1 , j) * Pa % Mod + (LL)get_dp (i, i + j) * Pb % Mod) % Mod; } inline void Solve () { printf ("%d\n" , get_dp(1 , 0 )); } inline void Input () { K = read<int >(), Pa = read<int >(), Pb = read<int >(); Pa = (LL)Pa * Pow(Pa + Pb, Mod - 2 ) % Mod; Pb = (1 - Pa + Mod) % Mod; Div = (LL)Pa * Pow(Pb, Mod - 2 ) % Mod; } int main () {#ifndef ONLINE_JUDGE freopen("D.in" , "r" , stdin ); freopen("D.out" , "w" , stdout ); #endif Input(); Solve(); return 0 ; }