[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;
}
原文地址:https://www.cnblogs.com/PPLPPL/p/13636941.html