CF1342E Placing Rooks

https://www.luogu.com.cn/problem/CF1342E

一看就很容斥

第一个限制条件相当于强制每行都有或每列都有
可以只考虑一个,然后最后让答案 ∗ 2 *2 2(当 k k k不为 0 0 0时)

假设每一行都有, m m m列有棋子,那么会产生 n − m n-m nm对,所以 m = n − k m=n-k m=nk
n n n个不同的棋子塞到 m m m列里面,显然是第二类斯特林数

答案就是 ( n n − k ) S ( n , n − k ) ( n − k ) ! \binom{n}{n-k}S(n,n-k)(n-k)! (nkn)S(n,nk)(nk)!
最后那个阶乘表示的是选出来的行和 列匹配的方案数

我们来回忆一下怎么求第二类斯特林数
首先是经典的次幂转下降幂
x n = ∑ i = 0 S ( n , i ) x i = ∑ i = 0 S ( n , i ) ( x i ) i ! x^n=\sum_{i=0}S(n,i)x^{i\over{}}=\sum_{i=0}S(n,i)\binom{x}{i}i! xn=i=0S(n,i)xi=i=0S(n,i)(ix)i!
二项式反演一手

S ( n , m ) = 1 m ! ∑ i = 0 ( − 1 ) m − i ( m i ) i n S(n,m)=\frac{1}{m!}\sum_{i=0}(-1)^{m-i}\binom{m}{i}i^n S(n,m)=m!1i=0(1)mi(im)in
code:

#include<bits/stdc++.h>
#define mod 998244353
#define N 200050
#define ll long long
using namespace std;
ll qpow(ll x, ll y) {
    ll ret = 1;
    for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
    return ret;
}
ll fac[N], ifac[N];
void init(int n) {
    fac[0] = 1;
    for(int i = 1; i <= n; i ++) fac[i] = fac[i - 1] * i % mod;
    ifac[n] = qpow(fac[n], mod - 2);
    for(int i = n - 1; i >= 0; i --) ifac[i] = ifac[i + 1] * (i + 1) % mod;
}
ll C(int n, int m) {
    return fac[n] * ifac[m] % mod * ifac[n - m] % mod;
}
ll S(int n, int m) {
    ll ret = 0;
    for(int i = 0; i <= m; i ++) ret = (ret + qpow(mod - 1, m - i) * C(m, i) % mod * qpow(i, n) % mod) % mod;
    return ret * ifac[m] % mod;
}
int n, k;
int main() {
    scanf("%d%d", &n, &k);
    if(k >= n) {
        printf("0");
        return 0;
    }
    init(n);
    ll ans = S(n, n - k) * C(n, n - k) % mod * fac[n - k] % mod;
    if(k) ans = ans * 2 % mod;
    printf("%lld", ans);
    return 0;
}

posted @ 2021-10-12 07:26  lahlah  阅读(41)  评论(0编辑  收藏  举报