Placing Rooks-CF 1342E

题意:

在一个 \(n∗n\) 的棋盘上放置 \(n\) 个车,满足以下两个条件:
1.棋盘上的每一个空格子都能被至少一只车走到;
2.恰好存在 \(k\) 对车可以相互攻击;
求所有车的摆放方案数。
数据范围:\(1≤n≤2*10^5,0≤k≤\frac{n(n−1)}{2}\)

分析:

首先,要想满足条件1,那么每一行/列必然要都放。假设每一行都放了一个,那么对于列,可以发现,当一列放了 \(k\) 个时,该列可以相互攻击的棋子的对数为 \(k-1\)。 按照题目的要求,要求有 \(k\) 对的话,当 \(k\geq n\) 时,显然为 \(0\)。否则就要使得有 \(k\) 列为空。
所有结果为:

\[ans=C(n,k)*((n-k)^k-C(n-k,1)*(n-k-1)^n+C(n-k,2)*(n-k-2)^n)... \]

注意当 \(k\neq 0\) 时,要 \(\times\) 2。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int N=2e5+5;
ll c[N],inv[N];
void init(int m,int n)
{
    inv[1]=1;
    for(int i=2;i<=n;i++)
        inv[i]=1LL*(mod-mod/i)%mod*inv[mod%i]%mod;
    c[0]=1;
    for(int i=1;i<=m;i++)
        c[i]=c[i-1]*(m-i+1)%mod*inv[i]%mod;
}
ll power(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1)
            res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res%mod;
}
ll solve(int n,int k)
{
    k=min(k,n-k);
    ll res=1;
    for(int i=1;i<=k;i++)
        res=res*(n-i+1)%mod*inv[i]%mod;
    return res%mod;
}
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    if(k>=n)
        printf("0\n");
    else
    {
        int m=n-k;
        init(m,n);
        ll ans=power(1LL*m,1LL*n);
        for(int i=1;i<=n-k;i++)
        {
            if(i&1)
                ans=(ans-power(1LL*(m-i),1LL*n)*c[i])%mod;
            else
                ans=(ans+power(1LL*(m-i),1LL*n)*c[i])%mod;
        }
        ans=ans%mod*solve(n,k)%mod;
        if(k>0)
            ans=2*ans%mod;
        printf("%lld\n",(ans+mod)%mod);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/1024-xzx/p/12820882.html