首先要满足所有格子都能被攻击,棋子的放置一定是①每一行都有或者每一列都有。
(1)当 的时候,同时上面 个,答案就是 ,因为对于第一行有 个位置可放,第二行有 个位置号可放…答案就是
(2)当k>=n的时候,答案肯定是0,因为 最多放置的情况就是全部放一列或者一行。
(3)我们先只看把棋子放到每一行,对于列操作类似。
因为要满足k个相对视,所以必然会有n-k列空着,那么我们先选择n-k列出来放置,就是 ,
然后这n-k列已经选出来了,我们要把这n个不同的棋子放到n-k列里面(棋子不同的原因是因为所在的行不同),
然后问题就转化为把n个不同的球放到 个不同的盒子里.
记做 ,, , 含义就是把n个不同球分到m个相同的盒子,然后
这里因为盒子不同,所以需要乘上
所以最终的答案就是 (因为要加上列的情况,所以是2倍),但由于这里 ,$n^2求
S_2 nlogn S_2$(菜鸡不会)
题解里面给的就是用容斥来求的
我们来粗略证明一下:
这题要求的是不允许有空行(空盒子),所以我们有一个想法:用至少有0个空盒子-至少有1个空盒子。
现在我们来看一下至少有 个空盒子的用 求出来与实际上的情况的区别。
对于至少有0个空盒子,每种情况都只算了一次( )。
对于至少有1个空盒子,就有一部分被重复算了,
实际有2个空盒子的会被算2次。看下图:
那么如果直接用至少0个空盒子的减去至少1个空盒子的必然多减去一部分,那么就要加上多减去的一部分。
现在来看一下实际有4个空盒子在至少0,1,2,3,4,个空盒子情况下分别被算了多少次。
这样一来直接把4个空盒子的情况给减去了(因为相加为0了)
对于其他实际k个空盒子也是一样的道理,这样一轮下来都等于0(二项式某个定理:奇数项和=偶数项和)
所以 把所有空盒子的情况都给去掉了。
以上纯属自己理解,如有错误,还请指出。
最后代码就好写了
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
typedef long long ll;
const ll mod = 998244353;
ll quick_(ll a,ll b){
ll ans = 1;
while(b){
if(b&1)ans = ans * a % mod;
a = a * a % mod ;
b >>= 1;
}
return ans;
}
ll fac[man];
void init(int n){
fac[0] = 1;
for(int i = 1;i <= n;i++){
fac[i] = i * fac[i-1] % mod;
}
}
ll C(ll n,ll m){
return fac[n] * quick_(fac[m],mod-2) % mod * quick_(fac[n-m],mod-2) % mod;
}
int main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int n,k;
cin >> n >> k;
if(k>n){
cout << 0 << endl;
}else if(k==0){
ll ans = 1;
for(int i = 1;i <= n;i++){
ans = ans * i % mod;
}
cout << ans << endl;
}else{
ll m = n - k;
init(n);
ll ans = C(n,m),sum = 0;
for(int i = 0;i < m;i++){
sum = (sum + (i&1 ? -1 : 1)*C(m,m-i)*quick_(m-i,n)%mod + mod)%mod;
}
ans = 2 * ans * sum % mod;
cout << ans << endl;
}
return 0;
}