LINK:Placing Rooks
丢人现场.jpg
没看到题目中的条件 放n个rook 我以为可以无限放 自闭了好半天。
其实只用放n个。那么就容易很多了。
可以发现 不管怎么放 所有列/所有行 都必须得放有。
那么最多只有n-1个pairs 当k==0时 容易发现是一个n!.
总之还是迷了很久。一道比较锻炼我当前水平的计数题。
有k行空着 比较显然 因为一旦多加一对 那么两个棋子就会放在同一行。
考虑计算出方案数 容易发现一开始的方案数为 \(C(n,k)\cdot (n-k)^n\)必然会有不合法的情况。
因为此时的含义是 至少有k行空着的方案数。需要-掉k+1行空着-k+2行空着...的方案数。
我们显然无法直接求出恰好有k+1行空着的方案数。如果可以直接求出恰好k行空着的就行辣。
考虑容斥 值得一提的是这样容斥会出错容斥系数不对。
如果至少k+1行空着的方案数也不对因为刚才的方案数再乘上后面的乘积营造了多种局面下的k+1行空着甚至一些局面是重复的。
而直接减掉只能减掉一部分。
做法:在原来的情况下进行容斥 在选出k个空行的时候考虑此时多选出了一行空着的-多选出两行空着的+...
这样容斥的系数就对了。
const ll MAXN=200010;
ll n,k;
ll fac[MAXN],inv[MAXN];
inline ll C(ll a,ll b){if(a<b)return 0;return fac[a]*inv[b]%mod*inv[a-b]%mod;}
inline ll ksm(ll b,ll p)
{
ll cnt=1;
while(p)
{
if(p&1)cnt=cnt*b%mod;
b=b*b%mod;p=p>>1;
}
return cnt;
}
signed main()
{
freopen("1.in","r",stdin);
get(n);get(k);
if(k>=n){puts("0");return 0;}
fac[0]=1;
rep(1,n,i)fac[i]=fac[i-1]*i%mod;
inv[n]=ksm(fac[n],mod-2);
fep(n-1,0,i)inv[i]=inv[i+1]*(i+1)%mod;
if(!k)putl(fac[n]);
else
{
ll ans=0;
rep(k,n,i)
{
ans=(ans+(((k-i)&1)?-1:1)*C(n,k)*C(n-k,i-k)%mod*ksm(n-i,n))%mod;
}
putl((ans+mod)%mod*2%mod);
}
return 0;
}