网格染色 [组合计数]

网格染色

N×MN \times M 的网格图, 给任意多个网格染色, 计算 使得每行每列至少有一个染色网格 的 染色方案数 .

N,M106N, M \le 10^6


\color{red}{正解部分}

答案 == 都合法的总方案数 - 合法前提下 不合法的方案数 .

都合法的总方案数 == (2n1)m(2^n - 1)^m, 不合法的方案数 =i=1N(1)i(ni)(2ni1)m= \sum\limits_{i=1}^N (-1)^i \begin{pmatrix} n \\ i \end{pmatrix}(2^{n-i} - 1)^m .

ans=i=0N(1)i(ni)(2ni1)m\therefore ans = \sum\limits_{i=0}^N (-1)^i \begin{pmatrix} n \\ i \end{pmatrix}(2^{n-i} - 1)^m .


\color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register

const int maxn = 1e6 + 5;
const int mod = 998244353;

int N;
int M;
int pw[maxn];
int inv[maxn];
int fac[maxn];
int ifac[maxn];

char S[maxn];

int C(int n, int m){ return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod; }

int Ksm(int a, int b){
        int s = 1;
        while(b){
                if(b & 1) s = 1ll*s*a % mod;
                a = 1ll*a*a % mod; b >>= 1;
        }
        return s;
}

int main(){
        scanf("%d%d", &N, &M); 
        scanf("%s", S+1); int t = N;
        for(reg int i = 1; i <= t; i ++) if(S[i] == '.') N --;
        scanf("%s", S+1); t = M;
        for(reg int i = 1; i <= t; i ++) if(S[i] == '.') M --;
        inv[1] = 1; for(reg int i = 2; i <= std::max(N, M); i ++) inv[i] = ((-1ll*mod/i*inv[mod%i])%mod + mod) % mod;
        fac[0] = 1; for(reg int i = 1; i <= std::max(N, M); i ++) fac[i] = 1ll*fac[i-1]*i%mod;
        ifac[0] = 1; for(reg int i = 1; i <= std::max(N, M); i ++) ifac[i] = 1ll*ifac[i-1]*inv[i] % mod;
        pw[0] = 1; for(reg int i = 1; i <= std::max(N, M); i ++) pw[i] = 2ll*pw[i-1] % mod;
        int Ans = 0;
        for(reg int i = 0; i <= N; i ++){
                int add = 1ll*C(N, i)*Ksm(pw[N-i]-1, M)%mod;
                if(i & 1) add = -add;
                Ans = ((Ans + add)%mod + mod) % mod;
        }
        printf("%d\n", Ans);
        return 0;
}
posted @ 2019-10-25 14:43  XXX_Zbr  阅读(306)  评论(0编辑  收藏  举报