zoukankan      html  css  js  c++  java
  • [BZOJ2669][CQOI2012]局部极小值

    题目描述

    有一个(n)(m)列的整数矩阵,其中(1)(n*m)之间的每个整数恰好出现一次。如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值。

    给出所有局部极小值的位置,你的任务是判断有多少个可能的矩阵。

    Input

    输入第一行包含两个整数(n)(m)(1<=n<=4, 1<=m<=7)),即行数和列数。以下(n)行每行(m)个字符,其中“(X)”表示局部极小值,“(.)”表示非局部极小值。

    Output

    输出仅一行,为可能的矩阵总数除以(12345678)的余数。

    Sample Input

    3 2
    X.
    ..
    .X
    

    Sample Output

    60
    

    首先,我们发现矩阵的大小很小,而局部最小值的位置也很少,最多只有(8)个最小值。

    [egin{matrix} X & . & X &.&X&.&X \ . & . & . &.&.&.&. \ X & . & X &.&X&.&X \ . & . & . &.&.&.&. \ end{matrix} ]

    于是我们可以考虑爆搜,搜出局部最小值的位置,然后在对于每种局部最小值的方案计算方案数。

    对于每种局部最小值已知的情况,我们定义(dp[i][j])表示填到第(i)个数,局部最小值被填的状态为(j)的方案数。

    我们考虑计算出没种状态的随便填的位置为(Sum_i),则对于当前(dp[i][j])有两种抉择。

    1.随便填,即不对(j)造成影响,(dp[i][j]+=dp[i-1][j]*max(Sum_j-i+1,0))

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

    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)为局部最小值的数量。

    (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
    ", mod - Ans);
    }
     
    signed main() {
        _main();
        return 0;
    }
    
  • 相关阅读:
    CSS选择器的优先级
    SQL Server——死锁查看
    VS2008激活找不到密匙输入框
    迷茫的周一
    SQL Server 2012使用日常
    Excel默认去除开头的0
    PDA日常问题
    第一个.NET小程序
    网站发布
    IIS配置——常见问题
  • 原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11637757.html
Copyright © 2011-2022 走看看