• bzoj 2669 状压DP


      因为最多有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[8][10];
    int map[8][10],flag[8][10],w[30][1000],X[10],Y[10],tot[1000],tmp[8][10];
    int ans,sum,n,m;
    const int go[8][2]={{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}};
     
    int solve() {
        int cnt=0,x,y,flag;
        for (int i=1;i<=n;i++) 
            for (int j=1;j<=m;j++) if (map[i][j]) X[cnt]=i,Y[cnt++]=j;
        for (int p=0;p<(1<<cnt);p++) {
            tot[p]=0;
            memset(tmp,0,sizeof tmp);
            for (int i=0;i<cnt;i++) if (p&(1<<i)) tmp[X[i]][Y[i]]=1;
            for (int i=1;i<=n;i++) 
                for (int j=1;j<=m;j++) if (!tmp[i][j]) {
                    flag=1;
                    for (int k=0;k<8&&flag;k++) {
                        x=i+go[k][0],y=j+go[k][1];
                        if (x<1||x>n||y<1||y>m) continue;
                        if (tmp[x][y]) flag=0;
                    }
                    if (flag) tot[p]++;
            }
        }
        memset(w,0,sizeof w);
        w[0][0]=1;
        int opp;
        for (int i=1;i<=sum;i++) {
            for (int p=0;p<(1<<cnt);p++) if (w[i-1][p]) {  
                opp=0;
                for (int j=0;j<cnt;j++) if (!(p&(1<<j))) 
                    opp|=(1<<j),(w[i][p|(1<<j)]+=w[i-1][p])%=d39;
                (w[i][p]+=w[i-1][p]*(tot[opp]-(i-1))%d39)%=d39;
            }
       }
       return w[sum][(1<<cnt)-1];
    }
     
    void ie(int x,int y,int t){
        map[x][y]=1;
        int i,j,ret;
        for (int k=0;k<8;k++) {
            i=x+go[k][0],j=y+go[k][1];
            if (i<1||i>n||j<1||j>m) continue;
            if (flag[i][j]) continue;
            flag[i][j]=t;
        }
        ret=solve();
        ans=(ans+get(t)*ret)%d39;
        for (j=y+1;j<=m;j++) if (flag[x][j]==0) ie(x,j,t+1);
        for (i=x+1;i<=n;i++) 
            for (j=1;j<=m;j++) if (flag[i][j]==0) ie(i,j,t+1);
        map[x][y]=0;
        for (int k=0;k<8;k++) {
            i=x+go[k][0],j=y+go[k][1];
            if (i<1||i>n||j<1||j>m) continue;
            if (flag[i][j]==t) flag[i][j]=0;
        }
    }
     
    int main(){
        scanf("%d%d",&n,&m);
        int cur=1,x,y;
        sum=n*m;
        for (int i = 1;i <= n;i ++) {
            scanf("%s",s[i]);
            for (int j=0;j<m;j++)map[i][j+1]=s[i][j]=='X'?1:0;
        }
        for (int i=1;i<=n&&cur;i++) {
            for (int j=1;j<=m&&cur;j++) if (map[i][j]) {
                if (flag[i][j]==-1) cur=0;
                flag[i][j]=-1;
                for (int k=0;k<8;k++) {
                   x=i+go[k][0],y=j+go[k][1];
                   if (x<1||x>n||y<1||y>m) continue;
                   flag[x][y]=-1;
               }
           }
        }
        if (!flag) {
            printf("0
    ");
            return 0;
        }
        ans=solve();
        for (int i=1;i<=n;i++) 
            for (int j=1;j<=m;j++) if (flag[i][j]==0) ie(i,j,1);
        (ans+=d39)%=d39;
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    FastWeb2011互联网工具发布
    本站启用新型试用模式
    TDiode单相及三相整流电路辅助设计器发布
    DCOp直流多级电路计算机辅助设计软件下载
    OpDesign2阻容耦合放大电路辅助设计软件下载
    共享软件的思考
    IpAdr网络地址计算器2011发布
    使用JavaScript动态添加复选框Checkbox
    JQuery操作checkbox、radio
    如果Oracle中的字段和数据库的系统字段重名,怎么配置NHibernate的映射实体文件
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3625422.html
Copyright © 2020-2023  润新知