[BZOJ2669][CQOI2012]局部極小值

題目描述

有一個\(n\)\(m\)列的整數矩陣,其中\(1\)\(n*m\)之間的每一個整數剛好出現一次。若是一個格子比全部相鄰格子(相鄰是指有公共邊或公共頂點)都小,咱們說這個格子是局部極小值。node

給出全部局部極小值的位置,你的任務是判斷有多少個可能的矩陣。c++

Input

輸入第一行包含兩個整數\(n\)\(m\)\(1<=n<=4, 1<=m<=7\)),即行數和列數。如下\(n\)行每行\(m\)個字符,其中「\(X\)」表示局部極小值,「\(.\)」表示非局部極小值。spa

Output

輸出僅一行,爲可能的矩陣總數除以\(12345678\)的餘數。debug

Sample Input

3 2
X.
..
.X

Sample Output

60

首先,咱們發現矩陣的大小很小,而局部最小值的位置也不多,最多隻有\(8\)個最小值。
\[ \begin{matrix} X & . & X &.&X&.&X \\ . & . & . &.&.&.&. \\ X & . & X &.&X&.&X \\ . & . & . &.&.&.&. \\ \end{matrix} \]
因而咱們能夠考慮爆搜,搜出局部最小值的位置,而後在對於每種局部最小值的方案計算方案數。code

對於每種局部最小值已知的狀況,咱們定義\(dp[i][j]\)表示填到第\(i\)個數,局部最小值被填的狀態爲\(j\)的方案數。get

咱們考慮計算出沒種狀態的隨便填的位置爲\(Sum_i\),則對於當前\(dp[i][j]\)有兩種抉擇。input

1.隨便填,即不對\(j\)形成影響,\(dp[i][j]+=dp[i-1][j]*max(Sum_j-i+1,0)\)it

2.填到局部最小值上,即\(dp[i][j|1<<k]+=dp[i][j],k\notin i\)ast

dp[0][0] = 1;
rep(i, 1, n * m) ret(j, 0, 1 << tot) {
    dp[i][j] += (dp[i - 1][j] * max(0ll, Sum[j] - i + 1) ) % mod;
    rep(k, 1, tot)if (!(j & 1 << k - 1))dp[i][j | (1 << k - 1)] += dp[i - 1][j];
}

當前狀態的\(ans\)即爲\(dp[n*m][(1<<tot)-1]\)\(tot\)爲局部最小值的數量。class

\(Sum_j\)\(n*m-\)當前狀態全部局部最小值以及其周圍\(8\)個格子的數量。

因爲,一個矩陣可能重複被算屢次,因此咱們要容斥,根據添加的格子的數量進行容斥。

#include <bits/stdc++.h>
 
using namespace std;
 
#define int long long
#define reg register
#define clr(a,b) memset(a,b,sizeof a)
#define Mod(x) (x>=mod)&&(x-=mod)
#define abs(a) ((a)<0?-(a):(a))
#define debug(x) cerr<<#x<<"="<<x<<endl;
#define debug2(x,y) cerr<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl;
#define debug3(x,y,z) cerr<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl;
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(3,"Ofast","inline")
 
inline int Read(void) {
    int res = 0, f = 1;
    char c;
    while (c = getchar(), c < 48 || c > 57)if (c == '-')f = 0;
    do res = (res << 3) + (res << 1) + (c ^ 48);
    while (c = getchar(), c >= 48 && c <= 57);
    return f ? res : -res;
}
 
template<class T>inline bool Min(T &a, T const&b) {return a > b ? a = b, 1 : 0;}
template<class T>inline bool Max(T &a, T const&b) {return a < b ? a = b, 1 : 0;}
 
const int N = 3e2 + 5, M = 1e5 + 5, K = 10, mod = 12345678;
const int dx[8] = {1, 0, -1, 1, -1, 1, 0, -1};
const int dy[8] = { -1, -1, -1, 0, 0, 1, 1, 1};
 
bool MOP1;
 
int n, m, A[9][9], vis[9][9], us[9][9], dp[30][1 << 9], Sum[1 << 9], Ans;
 
char S[15];
 
inline int X(int x) {return (x + m - 1) / m;}
 
inline int Y(int x) {return x % m ? x % m : m;}
 
struct node {
    int x, y;
} B[15];
 
void dfs(int pos) {
    if (pos == n * m + 1) {
        int tot = 0;
        rep(i, 1, n)rep(j, 1, m)if (vis[i][j])B[++tot] = (node) {i, j};
        clr(dp, 0);
        ret(i, 0, 1 << tot) {
            clr(us, 0);
            int res = 0;
            rep(j, 1, tot)if (!(i & 1 << j - 1)) {
                int x = B[j].x, y = B[j].y;
                if (!us[x][y])us[x][y] = 1, res++;
                rep(k, 0, 7) {
                    int Dx = B[j].x + dx[k], Dy = B[j].y + dy[k];
                    if (Dx < 1 || Dy < 1 || Dx > n || Dy > m)continue;
                    if (!us[Dx][Dy])us[Dx][Dy] = 1, res++;
                }
            }
            Sum[i] = n * m - res;
        }
        dp[0][0] = 1;
        rep(i, 1, n * m) ret(j, 0, 1 << tot) {
            dp[i][j] += (dp[i - 1][j] * max(0ll, Sum[j] - i + 1) ) % mod, Mod(dp[i][j]);
            rep(k, 1, tot)if (!(j & 1 << k - 1))dp[i][j | (1 << k - 1)] += dp[i - 1][j], Mod(dp[i][j | (1 << k - 1)]);
        }
        int op = tot;
        rep(i, 1, n)rep(j, 1, m)if (A[i][j])op--;
        if (op & 1) Ans +=  dp[n * m][(1 << tot) - 1], Mod(Ans);
        else Ans +=  mod - dp[n * m][(1 << tot) - 1], Mod(Ans);
        return;
    }
    int x = X(pos), y = Y(pos);
    if (A[x][y]) {
        dfs(pos + 1);
        return;
    }
    int flag = 1;
    rep(i, 0, 7) {
        int Dx = x + dx[i], Dy = y + dy[i];
        if (vis[Dx][Dy])flag = 0;
    }
    if (flag) {
        vis[x][y] = 1;
        dfs(pos + 1);
        vis[x][y] = 0;
    }
    dfs(pos + 1);
}
 
bool MOP2;
 
void _main(void) {
    n = Read(), m = Read();
    rep(i, 1, n) {
        scanf("%s", S);
        ret(j, 0, m)vis[i][j + 1] = A[i][j + 1] = (S[j] == 'X');
    }
    Ans = 0;
    dfs(1);
    printf("%lld\n", mod - Ans);
}
 
signed main() {
    _main();
    return 0;
}
相關文章
相關標籤/搜索