codeforces 1153F Serval and Bonus Problem

思路

將原線段縮成1, 因爲線段長度不影響結果
2n個點將線段分成了2n+1條線段, 我們有理由認爲這2n+12n+1條子線段的期望等長。
證明:
第一條線段大於等於x的概率 (1x)2n(1-x)^{2n}
對上式求導,得等於x的概率 2n(1x)2n12n(1-x)^{2n-1}
第一段的長度期望爲 E1=2n01x(1x)2n1dx=12n+1E_{1}=2n\int^1_0 x(1-x)^{2n-1}dx=\frac{1}{2n+1}
歸納一下,後面也必然相同

考慮dp, 自然想到dp[i][j]表示爲第i個有j沒匹配的方案數, 方案數考慮每條線段的順序事先排好,然後前後匹配一下即可.
之前考慮用概率Wa了,因爲每種轉移往後的方案數不一定相等,及不是等概率的增刪。

#include<bits/stdc++.h>
using namespace std;

const int MAX_N = 4e3 + 5;
typedef long long ll;
ll dp[MAX_N][MAX_N];
ll r[MAX_N], f[MAX_N];
const ll mod = 998244353;
int n, k, l;

void init() {
	r[1] = 1; f[0] = 1;
	for (int i = 2; i < MAX_N; i++) r[i] = r[mod%i] * (mod - mod / i) % mod;
	for (int i = 1; i <MAX_N; i++) f[i] = f[i - 1]*i % mod;
}
//錯的原因: 取和用等概率的條件是剩下的各種情況數相同, 但顯然不同。
ll val_select(int turn, int now) {
	int died = (turn - now) / 2, left = n - now - died;
	bool ans = (0 <= now && now <= n - 1) && (0 <= died && died <= n) && 1 <= left;
	return ans;
}
ll val_remove(int turn, int now) {
	int died = (turn - now) / 2, left = n - now - died;
	bool  ans = (1 <= now && now <= n) && (0 <= died && died <= n) && 0 <= left;
	return ans*now;
}
ll mod_r(ll x) {
	ll res = 1, n = mod - 2;
	while (n) {
		if (n & 1) res = res * x%mod;
		x = x * x%mod; n >>= 1;
	}
	return res;
}
int main() {
	init();
	cin >> n >> k>>l;
	dp[0][0] = 1;
	for (int i = 1; i <=2*n; i++) {
		for (int j = 0; j <= min(n, i); j++) {
			dp[i][j] += dp[i - 1][j - 1] * val_select(i - 1, j - 1) % mod;
			dp[i][j] += dp[i - 1][j + 1] * val_remove(i - 1, j + 1) % mod;
		}
	}
	ll ans = 0;
	for (int i = 1; i <= 2 * n; i++) {
		for (int j = k; j <= n; j++) {
			ans = (ans + dp[i][j] * dp[2 * n - i][j] % mod*f[j]) % mod;
		}
	}
	ans = ans * r[2 * n + 1] % mod*l%mod * mod_r(dp[2*n][0])%mod;
	cout << ans << endl;
	//system("pause");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章