题意:
在一个 n ∗ n n*n n∗n 的棋盘上放置 n n n 个车,满足以下两个条件:
- 棋盘上的每一个空格子都能被至少一只车走到
- 恰好存在 k k k 对车可以相互攻击
求所有车的摆放方案数。
要满足第一个条件,则每一行/每一列都有一个车,两者至少满足其一。对于这两种情况是等价的,下面只考虑每一行都有车,最终结果乘 2 2 2 即可, k = 0 k=0 k=0 不需要 ∗ 2 *2 ∗2。
假设所有行都有一个车,把每一列单独考虑,如果一列放了 x x x 个车,那么一定会产生 x − 1 x-1 x−1 对,在满足情况的条件下,恰好有 k k k 列是空的,这个可以自己画一下。
那就是棋子都放到 n − k n−k n−k 列,一共 ( n − k ) n (n−k)^n (n−k)n 种情况,减去至少有 1 1 1 个空行的情况 ( n − k − 1 ) n C n − k 1 (n−k−1)^nC^1_{n−k} (n−k−1)nCn−k1 ,加上至少有 2 个空行的情况 ( n − k − 2 ) n C n − k 2 (n−k−2)^nC^2_{n−k} (n−k−2)nCn−k2,减去至少有 3 个空行 ( n − k − 3 ) n C n − k 3 (n−k−3)nC^3_{n−k} (n−k−3)nCn−k3 ,……经典容斥模型。
AC代码:
const int N = 2e5 + 10;
const int mod = 998244353;
ll fac[N];
int n, k;
void init()
{
fac[0] = 1;
rep(i, 1, N - 2)
fac[i] = fac[i - 1] * i % mod;
}
ll c(int x, int y)
{
return fac[x] * qpow(fac[y] * fac[x - y] % mod, mod - 2, mod) % mod;
}
int main()
{
init();
sdd(n, k);
if (k == 0)
{
pld(fac[n]);
return 0;
}
if (k >= n)
{
puts("0");
return 0;
}
ll ans = 0;
rep(i, 0, n - k)
ans += 1ll * qpow(mod - 1, i,mod) * c(n - k, i) % mod * qpow(n - k - i, n,mod) % mod;
ans %= mod;
ans = 2ll * ans % mod * c(n, n - k) % mod;
pld(ans);
return 0;
}