[CF1342E] Placing Rooks

前言

数学就要多练练

题目

洛谷

CF

讲解

首先易证当\(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;
}
posted @ 2020-09-09 08:54  皮皮刘  阅读(217)  评论(0编辑  收藏  举报