[容斥原理][HDU 6314][2018杭电多校训练2 F题] Matrix

[容斥原理][HDU 6314][2018杭电多校训练2 G题] Matrix

题目大意

给定一个(N imes M)的矩阵,要将矩阵的每个格子涂成白色或黑色,问使得矩阵至少有(A)(B)列被完全涂成黑色的方案数。

题解

(f[N][M])表示(N imes M)的矩阵任意行任意列都没有被完全涂成黑色的方案数。由容斥原理
(f[N][M]=sum_{r=0}^{N}sum_{c=0}^{M} C_N^r imes C_M^c imes (-1)^{r+c} imes 2^{(N-r)*(M-c)})

(Ans=sum_{x=A}^{N}sum_{y=B}^{M} C_N^x imes C_M^y imes f[N-x][M-y])

(=sum_{x=A}^{N}sum_{y=B}^{M} C_N^x imes C_M^y imes(sum_{r=0}^{N-x}sum_{c=0}^{M-y} C_{N-x}^r imes C_{M-y}^c imes (-1)^{r+c} imes 2^{(N-x-r)(M-y-c)}))

(=sum_{x=A}^{N}sum_{y=B}^{M}sum_{r=0}^{N-x}sum_{c=0}^{M-y} C_N^x imes C_M^y imes C_{N-x}^r imes C_{M-y}^c imes (-1)^{r+c} imes 2^{(N-x-r)(M-y-c)})

(C_N^x imes C_M^y imes C_{N-x}^r imes C_{M-y}^c=frac{N!}{x! imes (N-x)!} imes frac{M!}{y! imes (M-y)!} imes frac{(N-x)!}{r! imes (N-x-r)!} imesfrac{(M-y)!}{c! imes (M-y-c)!})

(=frac{N! imes M!}{x! imes y! imes r! imes c! imes p! imes q!})

(p=N-x-r,q=M-y-c),则

(Ans=sum_{x=A}^{N}sum_{y=B}^{M}sum_{r=0}^{N-x}sum_{c=0}^{M-y} frac{N! imes M!}{x! imes y! imes r! imes c! imes p! imes q!} imes (-1)^{r+c} imes 2^{pq})

(=sum_{x=A}^{N}sum_{y=B}^{M}sum_{r=0}^{N-x}sum_{c=0}^{M-y} frac{2^{pq}}{p! imes q!} imes frac{N! imes(-1)^r}{x! imes r!} imes frac{M! imes (-1)^c}{y! imes c!})

(x+r=N-p, y+c=M-q,Aleq x, Bleq y)

(Pre[s][A]) 表示满足(x+r=s,Aleq x)(frac{(-1)^r}{x! imes r!})的和,令(g[p][q]=frac{2^{pq}}{p! imes q!}),则

(Ans=N! imes M! imes sum_{p=0}^{N-A}sum_{q=0}^{M-B}Pre[N-p][A] imes Pre[M-q][B] imes g[p][q])

时间复杂度(O(NM))

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;

#define RG register int
#define LL long long

const LL MOD=998244353;
LL Inv[3010],InvFact[3010],Fact[3010],Pre[3010][3010];
int Pow2[9000010],g[3010][3010];
int N,M,A,B;

inline void Init(){
    Inv[1]=1;InvFact[1]=1;Fact[1]=1;
    InvFact[0]=Fact[0]=1;Pow2[0]=1;
    for(RG i=2;i<=3000;++i){
        Inv[i]=(MOD-MOD/i)*Inv[MOD%i]%MOD;
        InvFact[i]=(InvFact[i-1]*Inv[i])%MOD;
        Fact[i]=(Fact[i-1]*(LL)i)%MOD;
    }
    for(RG i=1;i<9000000;++i){ 
        Pow2[i]=Pow2[i-1]<<1;
        if(Pow2[i]>MOD) Pow2[i]-=MOD;
    }
    return;
}

inline void GetPre(){
    for(RG x=3000;x>=0;--x){
        for(RG r=0;r<=3000-x;++r){
            LL temp;
            if(r&1) temp=MOD-1;
            else temp=1;
            Pre[x+r][x]=(Pre[x+r][x]+((temp*InvFact[x])%MOD)*InvFact[r]%MOD)%MOD;
            Pre[x+r][x-1]=(Pre[x+r][x-1]+Pre[x+r][x])%MOD;
        }
        for(RG y=0;y<=3000;++y)
            g[x][y]=Pow2[x*y]*InvFact[x]%MOD*InvFact[y]%MOD;
    }
    return;
}

inline void Solve(){
    LL Ans=0;
    for(RG p=0;p<=N-A;++p)
        for(RG q=0;q<=M-B;++q){
            Ans=(Ans+(Pre[N-p][A]*Pre[M-q][B]%MOD)*g[p][q]%MOD);
            if(Ans>MOD) Ans-=MOD;
        }
    Ans=(((Ans*Fact[N])%MOD)*Fact[M])%MOD;
    printf("%lld
",Ans);
    return;
}

int main(){
    Init();
    GetPre();
    while(~scanf("%d%d%d%d",&N,&M,&A,&B))
        Solve();
    return 0;
}
原文地址:https://www.cnblogs.com/AEMShana/p/12568604.html