1. 程式人生 > 實用技巧 >Solution -「CF 908D」New Year&Arbitrary Arrangement

Solution -「CF 908D」New Year&Arbitrary Arrangement

\(\mathcal{Description}\)

  Link.

  給定 \(n,p_a,p_b\),初始有一個空串,每次操作有 \(\frac{p_a}{p_a+p_b}\) 的概率在其後新增字元 \(\texttt{'a'}\)\(\frac{p_b}{p_a+p_b}\) 的概率新增字元 \(\texttt{'b'}\),當子序列 \(\{\texttt{'a'},\texttt{'b'}\}\) 的個數不小於 \(n\) 時,結束操作。求子序列的期望個數,對 \(10^9+7\) 取模。

  \(n\le1000\)

\(\mathcal{Solution}\)

  顯然狀態,\(f(i,j)\)

表示有 \(i\)\(\texttt{'a'}\)\(j\)\(\{\texttt{'a'},\texttt{'b'}\}\) 的期望串長。為方便轉移,令 \(p_a\) 為出現 \(\texttt{'a'}\) 的概率,\(p_b\) 同理。對於一般情況的轉移:

\[f(i,j)=p_af(i+1,j)+p_bf(i,i+j) \]

  當 \(i+j\ge n\),若再出現一個 \(\texttt{'b'}\),操作必然停止。那麼:

\[\begin{align} f(i,j)&=p_b\sum_{k=0}^{+\infty}p_a^k(i+j+k)\\ p_af(i,j)&=p_b\sum_{k=1}^{+infty}p_a^k(i+j+k-1)\\ (1-p_a)f(i,j)&=p_b\left(i+j+\sum_{k=1}^{+\infty}p_a^k\right)\\ p_bf(i,j)&=p_b\left(i+j+\frac{p_a}{p_b}\right)\\ f(i,j)&=i+j+\frac{p_a}{p_b} \end{align} \]

  而初始狀態有:

\[\begin{align} f(0,0)&=p_af(1,0)+p_bf(0,0)\\ &=\frac{p_a}{1-p_b}f(1,0)\\ &=f(1,0) \end{align} \]

  DP 就好了 w。

\(\mathcal{Code}\)

#include <cstdio>
#include <cstring>

typedef long long LL;

const int MAXN = 1000, MOD = 1e9 + 7;
int n, pa, pb, div, f[MAXN + 5][MAXN + 5];

inline int add ( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline int mul ( LL a, const int b ) { return ( a *= b ) < MOD ? a : a % MOD; }
inline int sub ( int a, const int b ) { return ( a -= b ) < 0 ? a : a + MOD; }

inline int qkpow ( int a, int b ) {
	int ret = 1;
	for ( ; b; a = mul ( a, a ), b >>= 1 ) ret = mul ( ret, b & 1 ? a : 1 );
	return ret;
}

inline int solve ( const int a, const int k ) {
	if ( a + k >= n ) return add ( a, add ( k, div ) );
	if ( ~ f[a][k] ) return f[a][k];
	return f[a][k] = add ( mul ( pa, solve ( a + 1, k ) ), mul ( pb, solve ( a, a + k ) ) );
}

int main () {
	int ta, tb;
	scanf ( "%d %d %d", &n, &ta, &tb );
	memset ( f, -1, sizeof f );
	pa = mul ( ta, qkpow ( add ( ta, tb ), MOD - 2 ) );
	pb = mul ( tb, qkpow ( add ( ta, tb ), MOD - 2 ) );
	div = mul ( pa, qkpow ( pb, MOD - 2 ) );
	printf ( "%d\n", solve ( 1, 0 ) );
	return 0;
}