1. 程式人生 > 實用技巧 >Solution -「AGC 019F」「AT 2705」Yes or No

Solution -「AGC 019F」「AT 2705」Yes or No

\(\mathcal{Description}\)

  Link.

  有 \(n+m\) 個問題,其中 \(n\) 個答案為 yes,\(m\) 個答案為 no。每次你需要回答一個問題,然後得知這個問題的正確答案。求最優策略下期望答對的題數。

  \(n,m\le5\times10^5\)

\(\mathcal{Solution}\)

  顯然貪心策略:當 \(n\not=m\),猜較多的答案。

  設 \(n>m\),無腦猜 yes,就一定能答對 \(n\) 道題。那麼所有 \(n\not=m\) 的情形下,猜對的期望次數之和就是 \(n\)。接下來只需要考慮 \(n=m\) 時的貢獻。

  其實 OEIS 能找到 www。首先,\(n=m\) 時,猜中的概率顯然為 \(\frac{1}2\)。那麼貢獻次數呢?考慮成一張為網格圖,從 \((0,0)\) 向下或向右走,走到 \((n,m)\),求進過 \((i,i)\) 的概率。這就是經典的組合數問題嘛。綜上,答案為:

\[\max\{n,m\}+\frac{1}{2\binom{n+m}{n}}\sum_{i=1}^{\min\{n,m\}}\binom{2i}{i}\binom{n+m-2i}{n-i} \]

  求出來就好啦,複雜度 \(\mathcal O(n+m)\)

\(\mathcal{Code}\)

#include <cstdio>

const int MAXN = 5e5, MOD = 998244353;
int n, m, fac[MAXN * 2 + 5], ifac[MAXN * 2 + 5];

inline int qkpow ( int a, int b, const int p = MOD ) {
	int ret = 1;
	for ( ; b; a = 1ll * a * a % p, b >>= 1 ) ret = 1ll * ret * ( b & 1 ? a : 1 ) % p;
	return ret;
}

inline void init ( const int n ) {
	fac[0] = 1;
	for ( int i = 1; i <= n; ++ i ) fac[i] = 1ll * i * fac[i - 1] % MOD;
	ifac[n] = qkpow ( fac[n], MOD - 2 );
	for ( int i = n - 1; ~ i; -- i ) ifac[i] = ( i + 1ll ) * ifac[i + 1] % MOD;
}

inline int C ( const int n, const int m ) {
	return n < m ? 0 : 1ll * fac[n] * ifac[m] % MOD * ifac[n - m] % MOD;
}

int main () {
	scanf ( "%d %d", &n, &m );
	if ( n < m ) n ^= m ^= n ^= m;
	init ( n + m );
	int ans = n, inv = ( MOD + 1ll ) / 2 * qkpow ( C ( n + m, n ), MOD - 2 ) % MOD;
	for ( int i = 1; i <= m; ++ i ) {
		ans = ( ans + 1ll * inv * C ( 2 * i, i ) % MOD * C ( n + m - 2 * i, n - i ) ) % MOD;
	}
	printf ( "%d\n", ans );
	return 0;
}