• [BZOJ2669] [cqoi2012]局部极小值


    [BZOJ2669] [cqoi2012]局部极小值

    Description

    有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次。如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值。给出所有局部极小值的位置,你的任务是判断有多少个可能的矩阵。

    Input

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

    Output

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

    Sample Input

    3 2
    X.
    ..
    .X

    Sample Output

    60

    试题分析

    数据范围那么小,由于两个局部极小值在八连通中挨着的时候,是没有合法情况的,所以局部极小值不会超过8个。
    这里要满足局部极小值集合严格为(S)的方案,这个严格看起来非常恶心,阻碍了我们的dp。
    那么就尝试利用容斥把这个严格去掉,枚举集合(F)使得(Sin F)
    这个枚举(F)的集合是(2^8)的。 我们按照从小到大填入局部极小值,一个状态不合法当且仅当一个不是局部极小值的位置填了而它八连通中的局部极小值没有填。
    所以(f_{i,j})为填到第(i)个数字,其中集合(j)的局部极小值已经填完。
    由状态可以得到转移方程:
    $ f_{i,j}=sum_{jin k} f_{i-1,j-{ k} }+f_{i-1,j} imes (g_j-(i-1)) ( 其中)g_j$表示去掉j的补集(还没有填的局部极小值)后还剩多少个格子。
    然后容斥即可。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
     
    using namespace std;
    #define LL long long
     
    inline LL read(){
        LL x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const LL INF = 2147483600;
    const LL MAXN = 100010;
    const LL Mod = 12345678;
     
    LL dis[10][2]={{0,1},{1,0},{0,-1},{-1,0},{-1,-1},{1,1},{-1,1},{1,-1},{0,0}};
    LL N,M; char str[11]; LL x[MAXN+1],y[MAXN+1];
    LL vis[11][11],nod[11][11]; LL ans;
     
    inline void setting(LL x,LL y,LL g){
        for(LL k=0;k<9;k++){
            LL xx=x+dis[k][0],yy=y+dis[k][1];
            if(xx<1||yy<1||xx>N||yy>M) continue;
            vis[xx][yy]+=g; 
        } return ;
    }
    LL ret=0;
    inline void setting2(LL x,LL y,LL g){
        for(LL k=0;k<9;k++){
            LL xx=x+dis[k][0],yy=y+dis[k][1];
            if(xx<1||yy<1||xx>N||yy>M) continue;
            if(g==1) {if(!nod[xx][yy]) nod[xx][yy]=1,--ret;}
            else nod[xx][yy]=0;
        } return ;
    }
    LL g[(1<<9)]; LL cnt;
    inline void Pre(){
        for(LL i=0;i<(1<<cnt);i++){
            ret=N*M;
            for(LL j=1;j<=cnt;j++)
                if((i>>(j-1))&1) setting2(x[j],y[j],1);
            g[(1<<cnt)-1-i]=ret;
            for(LL j=1;j<=cnt;j++)
                if((i>>(j-1))&1) setting2(x[j],y[j],-1);
        } return ;
    }
    LL f[7*7][(1<<9)];
    inline void dp(LL x){
        f[0][0]=1;
        for(LL i=1;i<=N*M;i++){
            for(LL j=0;j<(1<<cnt);j++){
                f[i][j]=0; //cout<<i<<endl;
                if(g[j]<=(i-1)) continue; //cout<<"t:"<<g[j]<<" "<<j<<" "<<i-1<<endl;
                if(j) for(LL k=1;k<=cnt;k++)
                    if((j>>(k-1))&1) f[i][j]+=f[i-1][j^(1<<(k-1))],f[i][j]%=Mod;
                f[i][j]+=f[i-1][j]*((g[j]-(i-1))%Mod+Mod)%Mod; f[i][j]%=Mod; 
            }
        } ans+=x*f[N*M][(1<<cnt)-1]%Mod;  //cout<<f[N*M][(1<<cnt)-1]<<endl;
        ans=(ans%Mod+Mod)%Mod; return ;
    }
    bool tt[17][17];
    inline void dfs(LL stp,LL flag,LL line,LL row){
        if(!stp){
            Pre(); dp(flag); return ;
        }
        for(LL i=line;i<=N;i++){
            for(LL j=(i==line?row:1);j<=M;j++){
                if(!vis[i][j]){
                    setting(i,j,1); x[++cnt]=i,y[cnt]=j;
                    dfs(stp-1,flag,i+(j+1>M?1:0),(j+1>M?1:j+1));
                    setting(i,j,-1); --cnt;
                }
            }
        } return ;
    }
     
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        N=read(),M=read();
        for(LL i=1;i<=N;i++){
            scanf("%s",str+1);
            for(LL j=1;j<=M;j++){
                if(str[j]=='X') {
                    x[++cnt]=i,y[cnt]=j;
                    setting(i,j,1);
                }
            }
        }
        for(LL stp=0;stp<=8-cnt;stp++){
            dfs(stp,(stp&1)?-1:1,1,1);
        } printf("%lld
    ",ans%Mod);
        return 0;
    }
    
  • 相关阅读:
    MFC9.0 Outlook控件的标题显示无法修改
    VS2010 单文档+多视图+Outlook风格
    在VS2010中使用Outlook工具栏
    在MFC中添加用户自定义消息
    读书笔记——Windows环境下32位汇编语言程序设计(13)关于EXCEPTION_DEBUG_INFO结构体
    读书笔记——Windows环境下32位汇编语言程序设计(9)ANSII字符大小写转大写
    读书笔记——Windows环境下32位汇编语言程序设计(6)使用浮点指令进行64位除法
    读书笔记——Windows环境下32位汇编语言程序设计(5)模态对话框
    读书笔记——Windows环境下32位汇编语言程序设计(3)一些基础知识
    设置自己的RadASM颜色
  • 原文地址:https://www.cnblogs.com/wxjor/p/9556606.html
Copyright © 2020-2023  润新知