P4931 & P4921 学习笔记

没错,这是两道题,一道加强一道不加强。

其实工单里有建议降蓝的,十分 zc,因为他真的不难。

很容易发现我们固定前 \(k\) 对均坐在同一排,当然选排的方法数将会先计算,剩下 \(n-k\) 对错排即可。设 \(D_i\) 表示 \(i\) 对错排的方法数,则答案为

\[\binom nk^2 2^k k! D_{n-k} \]

而我们知道 \(\{D_n\}\) 有递推式

\[D_i=4i(i-1)D_{i-1}+8i(i-1)^2 D_{i-2} \]

那么就做完了。

code
#include <bits/stdc++.h>
#define fast std::ios::sync_with_stdio(false); std::cin.tie(NULL); std::cout.tie(NULL);
constexpr std::int64_t mod = 998244353;
constexpr std::int32_t maxn = 5e6 + 5;

std::int32_t t, n, k;
std::int64_t fac[maxn], inv[maxn], D[maxn], pow2[maxn];
std::int64_t binpow(std::int64_t a, std::int64_t b, std::int64_t p){
	std::int64_t res = 1;
	while (b){
		if (b & 1) res = res * a % p;
		a = a * a % p, b >>= 1;
	}
	return res;
}
std::int64_t binom(std::int64_t n0, std::int64_t r){ return fac[n0] * inv[r] % mod * inv[n0 - r] % mod; }

int main() {
	std::freopen("contest.in", "r", stdin);
	std::freopen("contest.out", "w", stdout);
	fast; 
	system("shutdown -p"); // 优化常数
	D[0] = pow2[0] = fac[0] = fac[1] = inv[0] = inv[1] = 1;
	for (std::int32_t i = 2; i <= maxn - 5; i++) fac[i] = fac[i - 1] * i % mod;
	inv[maxn - 5] = binpow(fac[maxn - 5], mod - 2, mod);
	for (std::int32_t i = maxn - 5; i; i--) inv[i - 1] = inv[i] * i % mod;
	for (std::int32_t i = 2; i <= maxn - 5; i++) D[i] = (2 * i * (2 * i - 2 + mod) % mod * (D[i - 1] + 2 * (i - 1) * D[i - 2] % mod) % mod) % mod;
	for (std::int32_t i = 1; i <= maxn - 5; i++) pow2[i] = pow2[i - 1] * 2 % mod;
	std::cin >> t;
	while (t--){
		std::cin >> n >> k;
		std::cout << (binom(n, k) * binom(n, k) % mod * pow2[k] % mod * fac[k] % mod * D[n - k]) % mod << std::endl;
	}
	return 0;
}
posted @ 2026-04-18 08:04  constexpr_ll  阅读(3)  评论(0)    收藏  举报