• bzoj2669[cqoi2012]局部极小值 容斥+状压dp


    2669: [cqoi2012]局部极小值

    Time Limit: 3 Sec  Memory Limit: 128 MB
    Submit: 774  Solved: 411
    [Submit][Status][Discuss]

    Description

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

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

    Input

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

    Output

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

    Sample Input

    3 2
    X.
    ..
    .X

    Sample Output

    60

    容斥,推一推可以得到X的个数不超过8个(虽然我不知道是怎么推的)
    枚举,从小到大填数,状压dp可以计算出对于此种图的填数方案
    用cnt[s]表示状态s下可以填数的方案(包括之前已经填过的X但不包括没填的X)
    f[i][s]转移就得到啦(水一波)

    这样我们可以保证X的位置一定是周围最小的,但却不能保证其他位置不会出现多余的'X'
    于是我们dfs出每一个可以为X的地方,容斥一下就好啦
     
    推荐blog
    http://blog.csdn.net/popoqqq/article/details/48028773
     
    取模有毒
    a+=b;if(a>=mod)a-=mod;
    如果b是负数的话..就炸了!!
    调了1h..

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #define mod 12345678
    #define ll long long
    using namespace std;
    int n,m,tp,cnt[1<<9],ok[10][10];
    int dx[]={0,0,1,-1,1,-1,1,-1,0};
    int dy[]={1,-1,0,0,1,-1,-1,1,0};
    char mp[10][10];ll ans,f[30][1<<9];
    struct node{int x,y;}p[10];
    int dp(){
        memset(cnt,0,sizeof(cnt));
        memset(f,0,sizeof(f));tp=0;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if(mp[i][j]=='X')
        p[++tp]=(node){i,j};
        for(int st=0;st<(1<<tp);st++){
            memset(ok,0,sizeof(ok));
            for(int j=1;j<=tp;j++)
            if(!(st&(1<<(j-1))))ok[p[j].x][p[j].y]=1;
            for(int i=1;i<=n;i++)
            for(int k,j=1;j<=m;j++){
                for(k=0;k<9;k++)
                if(ok[i+dx[k]][j+dy[k]])break;
                if(k==9)cnt[st]++;
            }
        }
        f[0][0]=1;
        for(int i=1;i<=n*m;i++)
        for(int st=0;st<(1<<tp);st++){
            (f[i][st]+=f[i-1][st]*max(0,cnt[st]-i+1))%=mod;
            for(int k=1;k<=tp;k++)
            if((1<<(k-1))&st)(f[i][st]+=f[i-1][st^(1<<(k-1))])%=mod;
        }
        return f[n*m][(1<<tp)-1];
    }
    void dfs(int x,int y,int c){
        int t;
        if(x==n+1){
            (ans+=dp()*(c&1?-1:1))%=mod;
            return;
        }
        if(y==m)dfs(x+1,1,c);
        else dfs(x,y+1,c);
        for(t=0;t<9;t++)if(mp[dx[t]+x][dy[t]+y]=='X')break;
        if(t<9)return;
        mp[x][y]='X';
        if(y==m)dfs(x+1,1,c+1);
        else dfs(x,y+1,c+1);
        mp[x][y]='.';
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%s",mp[i]+1);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if(mp[i][j]=='X')
        for(int k=0;k<8;k++){
            int nx=i+dx[k],ny=j+dy[k];
            if(mp[nx][ny]=='X'){puts("0");return 0;}
        }
        dfs(1,1,0);
        ans<0?ans+=mod:1;
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    虚拟化技术KVM
    Rsync+Inotify实现文件自动同步
    第一次使用博客园
    kmp算法分析
    程序可移植性分析(一)数据类型
    strings用法小记
    size用法小记
    readelf用法小记
    nm用法小记
    ar用法小记
  • 原文地址:https://www.cnblogs.com/wsy01/p/8030019.html
Copyright © 2020-2023  润新知