1. 程式人生 > 其它 >【2022 省選訓練賽 Contest 15 A】set(數學)(組合數)(二項式定理)

【2022 省選訓練賽 Contest 15 A】set(數學)(組合數)(二項式定理)

set

題目連結:2022 省選訓練賽 Contest 15 A

題目大意

有 1~n 共 n 個數,然後問你隨機選 k 個,其中設其最小值為 x,求 T^x 的期望值。

思路

首先顯然列出一個式子(列舉哪個數作為最小值):
\(\dfrac{\sum\limits_{i=1}^nT^i\binom{n-i}{k-1}}{\binom{n}{k}}\)
然後下面先不管(反正可以 \(O(k)\) 求,就拆開來然後帶有 \(n\) 的階乘兩個消),所以就考慮怎麼求上面的。

先來看看程式碼的(豬鼻)推導。
\(1.\sum\limits_{i=1}^nT^i\binom{n-i}{k-1}\)
\(2.\sum\limits_{i=1}^n\sum\limits_{j=0}^i(T-1)^j\binom{i}{j}\binom{n-i}{k-1}\)

(二項式定理)
\(3.\sum\limits_{j=0}^n(T-1)^j\sum\limits_{i=1}^n\binom{i}{j}\binom{n-i}{k-1}\)\(i\) 可以不從 \(i\) 開始因為前面的答案都是 \(0\)
\(4.\sum\limits_{j=0}^n(T-1)^j\sum\limits_{i=1}^n\binom{n+k}{j+k}\)(你可以理解為兩個部分中間用一個選了的隔開,前面的選 \(j\) 個,後面的選 \(k-1\) 個)
\(5.T^{n+1}-\sum\limits_{j=0}^{k-1}\binom{n+1}{j}\)(把 \(T^{n+1}\)
二項式定理展開,然後容斥)
\(T^{n+1}=\sum\limits_{j=0}^{n+1}\binom{n+k}{j}(T-1)^j\)

首先發現一個顯然的錯誤:
\(5\) 中應該是 \(T^{n+1}-\sum\limits_{j=0}^{k-1}\binom{n+1}{j}T^{j}\)
然後你再看會發現其實它還有錯,就是 \(5\) 中應該整個式子除 \((T-1)^k\)
然後你按著寫發現錯了,然後你就檢查式子。

然後你會發現 \(4\) 有個小小的問題,就是你組合數的話 \(i=0\) 的情況時要計算的,但是前面 \(3\)\(i\)\(1\sim n\)
不過你會發現好像 \(i=0\)

的時候後面的部分都是 \(0\),但你很快會發現有一個特別的情況就是 \(j=0\),這個時候後面的式子是 \(\binom{j}{i}\binom{n-i}{k-1}=\binom{0}{0}\binom{n-0}{k-1}=\binom{n}{k-1}\)

所以你應該要減去一個 \(\binom{n}{k-1}\),而且你要注意的是後面的部分,你都除了 \((T-1)^k\),而你這個是不能除的,所以如果你前面都除了你這個的減去就要乘 \((T-1)^k\)

然後就終於可以過了TAT

程式碼

#include<cstdio>
#define ll long long
#define mo 998244353

using namespace std;

ll n, k, t, inv[10000001], all;

ll ksm(ll x, ll y) {
	ll re = 1;
	while (y) {
		if (y & 1) re = re * x % mo;
		x = x * x % mo; y >>= 1;
	}
	return re;
}

int main() {
	scanf("%lld %lld %lld", &n, &k, &t);
	
	if (t == 1) {//特判
		printf("1"); return 0;
	}
	
	inv[0] = inv[1] = 1; for (int i = 2; i <= k; i++) inv[i] = inv[mo % i] * (mo - mo / i) % mo;
	
	all = 1;
	for (int i = 1; i <= k; i++) all = all * (n - i + 1) % mo * inv[i] % mo;
	
	ll ans = ksm(t, n + 1), sum = 1;
	for (ll i = 0; i < k; i++) {
		ans = (ans - sum + mo) % mo;
		sum = sum * (n + 1 - (i + 1) + 1) % mo * inv[i + 1] % mo;
		sum = sum * (t - 1) % mo;
	}
	ll mor = 1;
	for (ll i = 1; i <= k - 1; i++) mor = mor * (n - i + 1) % mo * inv[i] % mo;
	ans = (ans - mor * ksm(t - 1, k) % mo + mo) % mo;
	ans = ans * ksm(ksm(t - 1, k), mo - 2) % mo;
	printf("%lld", ans * ksm(all, mo - 2) % mo);
	
	return 0;
}