前言
数学就要多练练
题目
讲解
首先易证当(n le k)时无解,(k=0)时答案为((n-1)!)
此时由于行和列是等价的,所以我们先只考虑对于每行只放一个车,最后将答案乘二即可
考虑放下一个车之后,如果当前列没有车,则对攻击数量不会有贡献,我们希望有(k)对车可以和互相攻击,则我们要放(n-k)列
对于(n)行,每行有(n-k)个位置可以放,则答案为(C_n^{n-k}*(n-k)^n)
吗?
很明显这样是错的,这样的统计会将放(le n-k)列的方案全部算进去,但我们需要的是恰好放(n-k)列的方案
典型的容斥,设(n-k)列中有(i)列一定为空,容斥式子为:
[S=sum_{i=0}^{n-k}(-1)^i*C_{n-k}^{i}*(n-k-i)^n
]
最终答案即为:
[C_n^{n-k}*S*2
]
代码
int qpow(int x,int y)
{
int ret = 1;
while(y){if(y & 1) ret = 1ll * ret * x % MOD;x = 1ll * x * x % MOD;y >>= 1;}
return ret;
}
int fac[MAXN],ifac[MAXN];
void pre(int x)
{
fac[0] = 1;
for(int i = 1;i <= x;++ i) fac[i] = 1ll * fac[i-1] * i % MOD;
ifac[x] = qpow(fac[x],MOD-2);
for(int i = x-1;i >= 0;-- i) ifac[i] = 1ll * ifac[i+1] * (i+1) % MOD;
}
int C(int x,int y)
{
if(x < y) return 0;
return 1ll * fac[x] * ifac[y] % MOD * ifac[x-y] % MOD;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read(); k = Read();
if(k >= n){Put(0);return 0;}
pre(200000);
if(!k){Put(fac[n]);return 0;}
for(int i = 0;i <= n-k;++ i)
{
LL f = (i&1) ? -1 : 1;
ans = (ans + f * C(n-k,i) * qpow(n-k-i,n)) % MOD;
}
ans = ans * C(n,n-k) * 2 % MOD;
Put((ans + MOD) % MOD);
return 0;
}