Placing Rooks 题解

看了半天题始终看不明白为什么 3 3 的样例输出 0,后来才发现车不能穿过别的车/lh

教练布置的二项式反演练习题,做完之后发现原来这个东西叫斯特林数?


先特判 $k = 0$ 或 $k \geqslant n$ 的情况,分别输出 $n!$ 和 $0$,一个是全排列一个是无解。

每一行或者每一列肯定都有一个车,并且如果有车能互相攻击到,那么要么都是攻击到同一列的车,要么都是攻击到同一行的车,这一点可以随便举几个例子感受一下。

具体证明的话:假设存在三个车,它们的坐标分别为 $(x_0, y_0)$,$(x_1, y_1)$,$(x_1, y_0)$,现在有两行/两列被覆盖到了,所以可以直接不考虑这两行/两列,把剩下的格子看成大小 $(n - 2) \times (n - 2)$ 的棋盘,我们要用 $n - 3$ 个车覆盖 $(n - 2) \times (n - 2)$ 的棋盘,这是不可能的。

有更多的车的情况也肯定不可能了。

所以要么每一行有且仅有一个车,某些车处于同一列从而产生互相攻击的关系;要么每一列有且仅有一个车,某些车处于同一行从而产生互相攻击的关系

下面讨论每一行有且仅有一个车的情况,因为棋盘是正方形的所以旋转一下就可以得到列的情况,最终答案乘 $2$ 即可。

令 $f(k)$ 表示钦定/至少有 $k$ 对可以互相攻击的车,令 $g(k)$ 表示恰好有 $k$ 对可以互相攻击的车。答案即为 $g(k)$。

由二项式反演(或者广义容斥原理)可以得到:

$$ f(k) = \sum\limits_{i = k}^{n}\binom{i}{k}g(i) \Leftrightarrow g(k) = \sum\limits_{i = k}^{n}(-1)^{i - k}\binom{i}{k}f(i) $$

考虑如何计算 $f(i)$。

因为我们讨论的是每一行都有车的情况,所以车能互相攻击到一定是因为在同一列里。如果同一列有 $cnt$ 个车,那么会贡献 $cnt - 1$ 对能够互相攻击的车,车的攻击判定是不能穿过别的车的

所以如果有 $i$ 对能够互相攻击到的车,那么肯定只有 $n - i$ 列上会有车。可以先选出是哪些列可以放车,再给每一行上的车分配它所在的列。所以 $f(i) = \binom{n}{n - i}(n - i)^{n}$。

直接计算 $g(k)$ 即可,时间复杂度 $\mathcal{O}(n \log n)$。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
ll n, k, ans, fct[200005], inv[200005];
ll ksm(ll x, ll y) {
    ll ret = 1;
    while(y) {
        if(y & 1) ret = ret * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ret;
}
ll c(ll n, ll m) {
    return fct[n] * inv[m] % mod * inv[n - m] % mod;
}
int gsm(int x) {return ((~x & 1) << 1) - 1;}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    fct[0] = 1;
    for(int i = 1; i <= 200000; ++i) fct[i] = fct[i - 1] * i % mod;
    inv[200000] = ksm(fct[200000], mod - 2);
    for(int i = 200000; i >= 1; --i) inv[i - 1] = inv[i] * i % mod;
    cin >> n >> k;
    if(k >= n) {
        cout << "0";
        return 0;
    }
    if(!k) {
        cout << fct[n];
        return 0;
    }
    for(int i = k; i <= n; ++i) {
        ans += gsm(i - k) * c(i, k) * c(n, n - i) % mod * ksm(n - i, n) % mod;
    }
    cout << (ans * 2 % mod + mod) % mod;
    return 0;
}
posted @ 2023-12-18 21:30  A_box_of_yogurt  阅读(5)  评论(0编辑  收藏  举报  来源
Document