Codeforces 1342 E Placing Rooks —— 第二類斯特林數

This way

題意:

現在有一個n*n的棋盤,n個棋子,你要放置這些棋子使得他們滿足以下條件:
每個格子都能被某個棋子打到
共有k對棋子能夠打到對方
如果一個格子所處的這一行或這一列有一個棋子,那麼這個格子就能被打到。兩個棋子處在同一行或同一列並且它們之間沒有別的棋子,這兩個棋子被視爲可以能夠打到對方。

題解:

這個就是第二類斯特林數的模板題,

第一類斯特林數:

你有n個不同棋子,要讓他構成m個環,有多少種組成方法
環是有序的,你每次要麼讓一個棋子自成一格環,要麼讓它加入某個棋子的左邊,於是
可以寫出這樣的方程:

dp[i][j]=dp[i-1][j-1]+dp[i-1][j-1]*i

第二類斯特林數:

你有n個不同的棋子,要將他們分成m個集合,有多少種組成方法
集合是無序的,它的方程式是這樣的:
S(n,m)=1m!i=0m(1)iCmi(mi)nS(n,m)=\frac{1}{m!}\sum_{i=0}^{m}(-1)^i*C_{m}^{i}*(m-i)^n
那麼這道題,首先要麼每行都有一個棋子,要麼每列都有一個棋子,行和列的考慮是相同的,所以最後*2即可。
由於有k對棋子可以打到對方,所以有n-k列含有1個或多個棋子,剩下的列一個棋子都沒有。所以這裏的情況數是CnnkC_{n}^{n-k}
然後就是S(n,nk)S(n,n-k)
由於所有棋子的行是不一樣的,所以n-k列是一個排列數:(nk)!(n-k)!
最後的答案就是CnnkS(n,nk)(nk)!C_{n}^{n-k}*S(n,n-k)*(n-k)!
=>Cnnki=0nk(1)iCnki(nki)n=>C_{n}^{n-k}*\sum_{i=0}^{n-k}(-1)^i*C_{n-k}^{i}*(n-k-i)^n

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+5;
const ll mod=998244353;
ll fac[N],inv[N],p[N];
ll qpow(ll a,ll b){ll ans=1;for(;b;b>>=1,a=a*a%mod)if(b&1)ans=ans*a%mod;return ans;}
ll c(ll n,ll m){
    if(m==0||m==n)return 1;
    if(m>n||m<0)return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    fac[0]=p[0]=1;
    if(k>n-1)
        return 0*printf("0\n");
    for(ll i=1;i<=n;i++)
        fac[i]=fac[i-1]*i%mod;
    inv[n]=qpow(fac[n],mod-2);
    for(ll i=n-1;i;i--)
        inv[i]=inv[i+1]*(i+1)%mod;
    ll ans=0,f=1;
    for(int i=0;i<=n-k;i++)
        ans=(ans+f*c(n-k,i)*qpow(n-k-i,n)%mod+mod)%mod,f*=-1;
    (ans*=c(n,n-k))%=mod;
    if(k!=0)ans=ans*2%mod;
    printf("%lld\n",ans);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章