因为最多有8个'X',所以我们可以用w[i][s]来表示现在我们填了前i个数,填的X的为S,因为每次新加进来的数都不影响前面的最小值,所以我们可以随便添加,这样就有了剩下所有位置的方案,每次都这样转移。

  但是这样会造成不是规定的地方出现局部最小值的情况,对于这样的情况,我们只需要枚举所有可能成为局部最小值的不合法状态来做容斥就可以了。

  反思:这道题的容斥开始写错了,本来应该是判奇偶来判断正负,写成了全是负的,还是A了,应该是后面的容斥没有合法方案所以符号无所谓的关系,真是rp++。

/**************************************************************
    Problem: 2669
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:928 kb
****************************************************************/
 
//By BLADEVIL
#include <cstdio>
#include <cstring>
#define d39 12345678
#define get(x) ((x&1)?-1:1)
 
using namespace std;
 
char s[][];
int map[][],flag[][],w[][],X[],Y[],tot[],tmp[][];
int ans,sum,n,m;
const int go[][]={{-,-},{-,},{-,},{,},{,},{,},{,-},{,-}};
 
int solve() {
    int cnt=,x,y,flag;
    for (int i=;i<=n;i++)
        for (int j=;j<=m;j++) if (map[i][j]) X[cnt]=i,Y[cnt++]=j;
    for (int p=;p<(<<cnt);p++) {
        tot[p]=;
        memset(tmp,,sizeof tmp);
        for (int i=;i<cnt;i++) if (p&(<<i)) tmp[X[i]][Y[i]]=;
        for (int i=;i<=n;i++)
            for (int j=;j<=m;j++) if (!tmp[i][j]) {
                flag=;
                for (int k=;k<&&flag;k++) {
                    x=i+go[k][],y=j+go[k][];
                    if (x<||x>n||y<||y>m) continue;
                    if (tmp[x][y]) flag=;
                }
                if (flag) tot[p]++;
        }
    }
    memset(w,,sizeof w);
    w[][]=;
    int opp;
    for (int i=;i<=sum;i++) {
        for (int p=;p<(<<cnt);p++) if (w[i-][p]) { 
            opp=;
            for (int j=;j<cnt;j++) if (!(p&(<<j)))
                opp|=(<<j),(w[i][p|(<<j)]+=w[i-][p])%=d39;
            (w[i][p]+=w[i-][p]*(tot[opp]-(i-))%d39)%=d39;
        }
   }
   return w[sum][(<<cnt)-];
}
 
void ie(int x,int y,int t){
    map[x][y]=;
    int i,j,ret;
    for (int k=;k<;k++) {
        i=x+go[k][],j=y+go[k][];
        if (i<||i>n||j<||j>m) continue;
        if (flag[i][j]) continue;
        flag[i][j]=t;
    }
    ret=solve();
    ans=(ans+get(t)*ret)%d39;
    for (j=y+;j<=m;j++) if (flag[x][j]==) ie(x,j,t+);
    for (i=x+;i<=n;i++)
        for (j=;j<=m;j++) if (flag[i][j]==) ie(i,j,t+);
    map[x][y]=;
    for (int k=;k<;k++) {
        i=x+go[k][],j=y+go[k][];
        if (i<||i>n||j<||j>m) continue;
        if (flag[i][j]==t) flag[i][j]=;
    }
}
 
int main(){
    scanf("%d%d",&n,&m);
    int cur=,x,y;
    sum=n*m;
    for (int i = ;i <= n;i ++) {
        scanf("%s",s[i]);
        for (int j=;j<m;j++)map[i][j+]=s[i][j]=='X'?:;
    }
    for (int i=;i<=n&&cur;i++) {
        for (int j=;j<=m&&cur;j++) if (map[i][j]) {
            if (flag[i][j]==-) cur=;
            flag[i][j]=-;
            for (int k=;k<;k++) {
               x=i+go[k][],y=j+go[k][];
               if (x<||x>n||y<||y>m) continue;
               flag[x][y]=-;
           }
       }
    }
    if (!flag) {
        printf("0\n");
        return ;
    }
    ans=solve();
    for (int i=;i<=n;i++)
        for (int j=;j<=m;j++) if (flag[i][j]==) ie(i,j,);
    (ans+=d39)%=d39;
    printf("%d\n",ans);
    return ;
}

bzoj 2669 状压DP的更多相关文章

  1. bzoj 1879 状压dp

    879: [Sdoi2009]Bill的挑战 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 852  Solved: 435[Submit][Status ...

  2. bzoj 1087 状压dp

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4130  Solved: 2390[Submit][ ...

  3. BZOJ 2064 - 状压DP

    传送门 题目大意: 给两个数组, 数组中的两个元素可以合并成两元素之和,每个元素都可以分裂成相应的大小,问从数组1变化到数组2至少需要多少步? 题目分析: 看到数据范围\(n<=10\), 显然 ...

  4. BZOJ 4057 状压DP

    思路: 状压一下 就完了... f[i]表示选了的集合为i 转移的时候判一判就好了.. //By SiriusRen #include <cstdio> #include <cstr ...

  5. BZOJ 4565 状压DP

    思路: f[i][j][S]表示从i到j压成S状态 j-m是k-1的倍数 $f[i][j][S<<1]=max(f[i][j][S<<1],f[i][m-1][S]+f[m][ ...

  6. bzoj 1072状压DP

    1072: [SCOI2007]排列perm Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2293  Solved: 1448[Submit][St ...

  7. bzoj 1072 状压DP

    我们用w[i][j]来表示,i是一个二进制表示我们选取了s中的某些位,j表示这些位%d为j,w[i][j]则表示这样情况下的方案数,那么我们可以得到转移.w[i|(1<<k)][(j*10 ...

  8. bzoj 1076 状压DP

    我们设w[i][s]为当前到第i关,手中的物品为s的时候,期望得分为多少,其中s为二进制表示每种物品是否存在. 那么就比较容易转移了w[i][s]=(w[i-1][s']+v[j]) *(1/k),其 ...

  9. BZOJ 1231 状压DP

    思路: f[i][j] i表示集合的组成 j表示选最后一个数 f[i][j]表示能选的方案数 f[i|(1<< k)][k]+=f[i][j]; k不属于i j属于i且符合题意 最后Σf[ ...

随机推荐

  1. lol人物模型提取(一)

      前段时间去青岛搞团建去了,闲来无事逛了会儿淘宝,无想买个lol手办,意之间发现了这张店铺宣传图:   哎呀我去,这模型做得挺逼真啊,然而这家店铺是卖zoe的cosplay道具的,不是手办-_-|| ...

  2. 基于c++和opencv底层的图像旋转

    图像旋转:本质上是对旋转后的图片中的每个像素计算在原图的位置. 在opencv包里有自带的旋转函数,当你知道倾斜角度theta时: 用getRotationMatrix2D可得2X3的旋转变换矩阵 M ...

  3. Spring MVC实践

    MVC 设计概述 在早期 Java Web 的开发中,统一把显示层.控制层.数据层的操作全部交给 JSP 或者 JavaBean 来进行处理,我们称之为 Model1: 出现的弊端: JSP 和 Ja ...

  4. 【bzoj1370】[Baltic2003]Gang团伙 并查集

    题目描述 在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足: 1. 我朋友的朋友是我的朋友: 2. 我敌人的敌人是我的朋友: 所有是朋友的人组成一个团伙.告诉你关于这n个人的m条信息, ...

  5. BZOJ3196 & 洛谷3380:二逼平衡树——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3196 https://www.luogu.org/problemnew/show/P3380 (题 ...

  6. [LNOI] 相逢是问候 || 扩展欧拉函数+线段树

    原题为2017六省联考的D1T3 给出一个序列,m次操作,模数p和参数c 操作分为两种: 1.将[l,r]区间内的每个数x变为\(c^x\) 2.求[l,r]区间内数的和%p 首先,我们要了解一些数论 ...

  7. PLAN OF HEOI(unfinished)

    Au:整体二分/计算几何/多项式/fwtAg:可持久化重量平衡树/线段树分治/线段树合并/最短路树/最短路DAGCu:三分Up:博弈论/置换群/杜教筛/矩阵树定理/BSGS/动态树分治/网络流(线性规 ...

  8. 学习tcpIp必备的抓包工具wireshark

    wireshark是一个优秀的抓包工具 ip.src=192.168.10.123  发送http的一端 ip.dst=192.168.10.126 接收http的一端 如下图所示:

  9. 编译skia静态库时,图片解码库无法注册的问题

    转载:http://www.cnblogs.com/imlucky/archive/2012/08/01/2617851.html 今天编译skia库,增加图片解码库时总是无效.按照此博客的方法修改后 ...

  10. 解决iText2.0.8+freemark导出pdf不支持base64的解决办法

    转换工具类 public class B64ImgReplacedElementFactory implements ReplacedElementFactory { /** * 实现createRe ...