CF1342E Placing Rooks

Solution

一共只有 \(n\) 辆车,如果两两之间不攻击又要使所有空格子被攻击到,那么就是一个排列 \(n!\)。现在我们想使其中一对能互相攻击到,就需要将其中一辆车移到另一行或另一列,那么这辆车原来所在的行或列就会空出来,又要使每个空格子被攻击到,那么就要保证每一列或每一行都至少要有一辆车,所以计数的时候让每辆车对应一列或一行。

不妨钦定每行有一个车,如果 \(k=0\),那么答案是 \(n!\),否则我们计数当前钦定下的方案,然后翻转就得到另一种,于是最后答案是两倍。在当前钦定下,相当于有且仅有 \(n-k\) 列有车,那么就是将 \(n\) 个元素划分到 \(k\) 个不同非空集合的方案数,容斥即可。

#include<stdio.h>
#define N 200007
#define ll long long

const int Mod = 998244353 ;

ll fac[N],inv[N];

ll qpow(ll x,ll y){
    ll ret=1,cnt=0;
    while(y>=(1LL<<cnt)){
        if(y&(1LL<<cnt)) ret=(ret*x)%Mod;
        x=(x*x)%Mod,cnt++;
    }
    return ret;
}

ll C(ll x,ll y){return x<y? 0:fac[x]*inv[y]%Mod*inv[x-y]%Mod;}

ll n,K;
int main(){
    //freopen("Data.in","r",stdin);
    fac[0]=1;
    for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%Mod;
    inv[N-1]=qpow(fac[N-1],Mod-2);
    for(int i=N-2;~i;i--) inv[i]=inv[i+1]*(i+1)%Mod;
    scanf("%lld%lld",&n,&K);
    if(K>=n) printf("0");
    else{
        ll ans=0;
        for(int i=K,op=1;i<=n;i++,op=-op)
            ans=(ans+op*C(i,K)*C(n,i)%Mod*qpow(n-i,n)%Mod+Mod)%Mod;
        printf("%lld",!K? ans:ans*2%Mod);
    }
}
posted @ 2021-01-16 12:41  Kreap  阅读(34)  评论(0编辑  收藏  举报