CF1342E Placing Rooks 题解

CF1342E Placing Rooks

首先答案满足每行有一个棋子或每列有一个棋子,否则假设某一行没有棋子,则为了覆盖这一行需要每一列都有一个棋子,矛盾。某一列没有棋子同理。因此,最多只能把棋子摆成一排,产生 \(k-1\) 对碰撞。

行和列等价,我们先考虑每行有一个棋子的情况。假设每一列都只有一颗棋子,如果需要产生 \(k\) 对棋子可以相互攻击,则需要将 \(k\) 列的棋子移动到别的列,最后总共有 \(n-k\) 列有棋子。

首先选出 \(n-k\) 列的编号,方案数为 \(\binom{n}{n-k}\)。然后假设每列相同,由于棋子所在的行不同所以本质不同,相当于有区别的求放进无区别的盒子里,方案数为 \(n\brace n-k\)。最后由于每列不同,分配编号,方案数为 \((n-k)!\)。最终的式子为 \(\binom{n}{n-k}{n\brace n-k}(n-k)!\)。第二类斯特林数可以直接使用通项公式计算。

注意 \(k\ne0\) 时还需要考虑每列有一个棋子的情况,与每行有一个棋子的情况相同,乘以 \(2\) 即可。

#include <bits/stdc++.h>
using namespace std;
long long n,k,jc[300000],inv[300000],ans=0;
const long long mod=998244353;
long long power(long long a,long long p)
{
	long long x=a,ans=1;
	while(p)
	   {
	   	if(p&1)ans=ans*x%mod;
	   	p>>=1;
	   	x=x*x%mod;
	   }
	return ans;
}

long long c(long long n,long long k)
{
	return jc[n]*inv[n-k]%mod*inv[k]%mod;
}

long long strl(long long n,long long m)
{
	long long ans=0;
	for(int i=0;i<=m;i++)ans=(ans+power(-1,m-i)*power(i,n)%mod*inv[i]%mod*inv[m-i]%mod)%mod;
    return (ans%mod+mod)%mod;
}

int main()
{
	jc[0]=1;
	for(int i=1;i<=200000;i++)jc[i]=jc[i-1]*i%mod;
	inv[200000]=power(jc[200000],mod-2)%mod;
	for(int i=199999;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
	scanf("%lld%lld",&n,&k);
	if(k>=n)printf("0\n");
	else if(k==0)printf("%lld\n",c(n,n-k)%mod*strl(n,n-k)%mod*jc[n-k]%mod);
	else printf("%lld\n",2*c(n,n-k)%mod*strl(n,n-k)%mod*jc[n-k]%mod);
	return 0;
}
posted @ 2025-07-20 15:13  w9095  阅读(11)  评论(0)    收藏  举报