题目大意

$n$ 排两列,塞 $n$ 对情侣,求恰好 $k$ 对情侣没有被拆散的数量。对 $998244353$ 取模。

题解

注意到,答案表达式为

$$\binom{n}{k}\cdot n^{\underline{k}}\cdot 2^k\cdot f_{n-k} $$

其中 $f_i$ $i$ 对情侣全被拆散的数量。有

$$f_i=4i(i-1)\left(f_{i-1}+2(i-1)f_{i-2}\right) $$

代码

const int N = 5e6 + 10, mod = 998244353;

inline ll read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

inline int add (int a, int b) { return a + b > mod? a + b - mod: a + b; }
inline int dec (int a, int b) { return a < b? a - b + mod: a - b; }
inline int mul (int a, int b) { return 1ll * a * b % mod; }

namespace Main {
	int n, k;
	int f[N];
	int fac[N], ifac[N], p2[N];

	int qpow (int a, int b) {
		int ans = 1;
		for (; b; b >>= 1, a = mul(a, a))
			if (b & 1) ans = mul(ans, a);
		return ans;
	}
	int binom(int n, int m) {
		if (m > n) return 0;
		return mul(fac[n], mul(ifac[m], ifac[n - m]));
	}

	int main () {
		fac[0] = p2[0] = 1;
		f[0] = 1, f[1] = 0;
		for (int i = 1; i <= N - 10; i++) {
			fac[i] = mul(fac[i - 1], i), p2[i] = mul(p2[i - 1], 2);
			if (i > 1) f[i] = add(mul(mul(mul(4, i), i - 1), f[i - 1]), 
					mul(mul(mul(mul(8, i), i - 1), i - 1), f[i - 2]));
		}
		ifac[N - 10] = qpow (fac[N - 10], mod - 2);
		for (int i = N - 10; i; --i) ifac[i - 1] = mul(ifac[i], i);

		for (int t = read(); t--; ) {
			n = read(), k = read();
			int ans = mul(binom(n, k), mul(p2[k], mul(fac[n], ifac[n - k])));
			ans = mul(ans, f[n - k]);
			printf ("%d\n", ans);
		}
		return 0;
	}
}

int main () {
	string str = "";
//	freopen((str + ".in").c_str(), "r", stdin);
//	freopen((str + ".out").c_str(), "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。