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
n−m对,所以
m
=
n
−
k
m=n-k
m=n−k
把
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)!
(n−kn)S(n,n−k)(n−k)!
最后那个阶乘表示的是选出来的行和 列匹配的方案数
我们来回忆一下怎么求第二类斯特林数
首先是经典的次幂转下降幂
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=0∑S(n,i)xi=i=0∑S(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)m−i(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;
}