CF1342E 题解

CF1342E 题解

题意: 给定一张 \(n \times n\) 大小的棋盘和 \(n\) 个国际象棋的车,求满足下列条件的放置方法数之和:

  1. 所有的空格子都能被至少一个车攻击到。
  2. 恰好\(k\) 对车可以互相攻击到。

\(n \leq 10^5,k \leq \frac {n(n+1)}{2}\).

做法:

首先,由条件 \(1\) 可知,不是每行都有一个车,就是每列都有一个车,而这两种本质等价。

故我们只考虑每行都有一个车,最后答案翻倍即可。

此时,能互相攻击到的车不可能在同一行,就只可能在同一列。

考虑到如果某一列上有 \(t\) 个车,这一列对能互相攻击的车对数造成的贡献是 \(t-1\)

故当 \(k \geq n\) 时,答案必然是 \(0\)

我们再考虑一个更强的性质:

如果有 \(x\) 列有车,那么能互相攻击的车对数 \(k\) 就等于 \(n-x\)

因为如果只有一列有车,则 \(k=n-1\)

而每多一列有车,设这些在新列的车数为 \(y\),它们原来对 \(k\) 的贡献是 \(y\),而现在贡献是 \(y-1\)

于是,我们就把问题转化为:

我们要将 \(n\) 个分别属于不同行的车放在若干列里,要求是有车的列有 \(n-k\) 个。

我们先钦定 \(n-k\) 列有车,问题就转化为,

我们要将 \(n\) 个分别属于不同行的车放在 \(n-k\) 列里,要求是每一列都有车。

这个问题的答案就是 \(S2(n,n-k) \times (n-k)!\),其中 \(S2\) 代表第二类斯特林数。

而钦定 \(n-k\) 列有车的方案是\(\binom {n}{n-k}\),也就是说最后的总答案就等于:

\(Ans=2 \times S2(n,n-k) \times (n-k)! \times \binom {n}{n-k}\)

code:

#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define int long long
#define pii pair < int , int >
#define swap(u, v) u ^= v, v ^= u, u ^= v
#define ckmax(a, b) ((a) = max((a), (b)))
#define ckmin(a, b) ((a) = min((a), (b)))
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
using namespace std;
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while (ch < '0' || ch > '9') f = ch == '-' ? -1 : 1, ch = getchar();
	while (ch >= '0' && ch <= '9') x = x * 10 + ch - 48, ch = getchar();
	return x * f;
}
const int N (2e5 + 10);
const int mod (998244353);
int n, k;
int fac[N];
int inv[N];
inline int ksm (int a, int b) {
	int r = 1;
	for (; b; a = a * a % mod, b >>= 1) if (b & 1) r = r * a % mod;
	return r;
}
inline int C (int bi, int sm) {
	return fac[bi] * inv[sm] % mod * inv[bi - sm] % mod;
}
inline int S (int ball, int box) {
	int r = 0, sgn = 1;
	rep (i, 0, box) {
		sgn = ((box- i) & 1) ? mod - 1 : 1;
		r = (r + C (box, i) * sgn % mod * ksm (i, ball) % mod) % mod;
	} return r * inv[box] % mod;
}

signed main() {
	n = read(), k = read(), fac[0] = inv[0] = 1;
	if (k >= n) return puts ("0"), 0;
	rep (i, 1, N - 5) fac[i] = fac[i - 1] * i % mod, inv[i] = ksm (fac[i], mod - 2);
	if (!k) return cout << fac[n], 0;
	int x = S (n, n - k) * C (n, n - k) % mod * fac[n - k] % mod * 2 % mod;
	cout << x;
	return 0;
}
posted @ 2021-12-03 17:13  GaryH  阅读(33)  评论(0编辑  收藏  举报