CF1342E 题解
CF1342E 题解
题意: 给定一张 \(n \times n\) 大小的棋盘和 \(n\) 个国际象棋的车,求满足下列条件的放置方法数之和:
- 所有的空格子都能被至少一个车攻击到。
- 恰好有 \(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;
}