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;
}

浙公网安备 33010602011771号