题意:
在一个 (n∗n) 的棋盘上放置 (n) 个车,满足以下两个条件:
1.棋盘上的每一个空格子都能被至少一只车走到;
2.恰好存在 (k) 对车可以相互攻击;
求所有车的摆放方案数。
数据范围:(1≤n≤2*10^5,0≤k≤frac{n(n−1)}{2})
分析:
首先,要想满足条件1,那么每一行/列必然要都放。假设每一行都放了一个,那么对于列,可以发现,当一列放了 (k) 个时,该列可以相互攻击的棋子的对数为 (k-1)。 按照题目的要求,要求有 (k) 对的话,当 (kgeq n) 时,显然为 (0)。否则就要使得有 (k) 列为空。
所有结果为:
[ans=C(n,k)*((n-k)^k-C(n-k,1)*(n-k-1)^n+C(n-k,2)*(n-k-2)^n)...
]
注意当 (k eq 0) 时,要 ( imes) 2。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int N=2e5+5;
ll c[N],inv[N];
void init(int m,int n)
{
inv[1]=1;
for(int i=2;i<=n;i++)
inv[i]=1LL*(mod-mod/i)%mod*inv[mod%i]%mod;
c[0]=1;
for(int i=1;i<=m;i++)
c[i]=c[i-1]*(m-i+1)%mod*inv[i]%mod;
}
ll power(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1)
res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res%mod;
}
ll solve(int n,int k)
{
k=min(k,n-k);
ll res=1;
for(int i=1;i<=k;i++)
res=res*(n-i+1)%mod*inv[i]%mod;
return res%mod;
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
if(k>=n)
printf("0
");
else
{
int m=n-k;
init(m,n);
ll ans=power(1LL*m,1LL*n);
for(int i=1;i<=n-k;i++)
{
if(i&1)
ans=(ans-power(1LL*(m-i),1LL*n)*c[i])%mod;
else
ans=(ans+power(1LL*(m-i),1LL*n)*c[i])%mod;
}
ans=ans%mod*solve(n,k)%mod;
if(k>0)
ans=2*ans%mod;
printf("%lld
",(ans+mod)%mod);
}
return 0;
}