2669: [cqoi2012]局部极小值

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 561  Solved: 293
[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

HINT

Source

Solution

这道题有点劲!自己没想出来,于是看的论文  传送门   下面引用论文里的题解

对于一个合法的数填写方案,其中的数放置的顺序对其是没有影响的,于是我们可以从1开始填数,并且一个一个地填进格子。如果采取这样的做法,那么所有的“X”必然要在其周边所有的格子填数之前就填好一个数,而"X"有多少呢?很显然最多只有8个而已。这时我们就可以想到这样的一个状态压缩方式:opt[i][j](j是一个二进制表达)表示的是i及其以后的数还没有填进格子,被填写了数的“X”集合状态为j的情况下的方案数。

如上图4*7的矩阵中,红色的"X"表示已经填写数的"X",红色的格子表示已经填写数的非"X"格子,那么可以表述成这样的状态opt[8][num](8表示已经填写了7个数,下一个填写8,num是011010的表示,含义是第2、3、5个"X"已经填写了数了)

如果我们转移的话就会有两种情况:

第一种情况就是把i填进一个"X"中,这个显然只要枚举一下放哪一个"X",然后把这个"X"加入j表示的集合里就可以了。

如上图,下一步我们填写"X"是可以随意的,因为只要存在解,任意的"X"都是互不影响的。当前的状态为f[8][num1](num1为011010的表示),可以推导到f[9][num2](num2为111010、011110、011011的表示)。

第二种情况就是把i填进一个非"X"中,这样的选择就有很多了。对于全图我们一共有n*m个格子,若没有填进去数的"X"格子以及其周边的格子共有tot个,显然这tot个格子都是不能填i的(因为填进的是一个非"X",并且一个没有填进去数的"X"格子其周边因为都要比它小,所以这两者都不可以填i),又因为已经填写了1到i-1所有的数,所以剩下能填的选择数就是n*m-tot-(i-1)。

如上图,所有的蓝色区域都是无法填写i的,而下一步能填写的格子就只有白色的格子,即4*7-17-7=4个格子。

由于这样的处理方式,尤其是第二种转移可能会导致非"X"点变为最小值,所以还需要使用容斥原理来解决。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define LL long long
#define P 12345678
int N,M,ANS,bin[],f[][],cnt[];
char mp[][];
int dx[]={-,-,-,,,,,,,},dy[]={-,,,-,,,-,,,};
inline bool OK(int x,int y) {return x>= && x<=N && y>= && y<=M;}
#define Pa pair<int,int>
Pa stack[]; int top;
bool visit[][];
inline void PreWork()
{
top=;
for (int i=; i<=N; i++)
for (int j=; j<=M; j++)
if (mp[i][j]=='X') stack[top++]=make_pair(i,j);
for (int i=; i<bin[top]; i++)
{
cnt[i]=; memset(visit,,sizeof(visit));
for (int j=; j<top; j++) if (~i&bin[j]) visit[stack[j].first][stack[j].second]=;
for (int j=; j<=N; j++)
for (int k=; k<=M; k++)
if (!visit[j][k])
{
bool flag=;
for (int d=,x,y; d<= && flag; d++)
x=j+dx[d],y=k+dy[d],flag=!visit[x][y];
cnt[i]+=flag;
}
}
}
inline int DP()
{
PreWork();
memset(f,,sizeof(f));
f[][]=;
for (int i=; i<=N*M; i++)
for (int j=; j<bin[top]; j++)
{
for (int k=; k<top; k++)
if (j&bin[k]) (f[i][j]+=f[i-][j^bin[k]])%=P;
(f[i][j]+=(LL)f[i-][j]*(cnt[j]-(i-))%P)%=P;
}
return f[N*M][bin[top]-];
}
inline void DFS(int dep,int x,int y)
{
if (y==M+) {DFS(dep,x+,); return;}
if (x==N+) {(ANS+=(LL)DP()*(dep&? -:)%P)%=P; return;}
DFS(dep,x,y+);
bool flag=;
for (int i=; i<= && flag; i++)
if (mp[x+dx[i]][y+dy[i]]=='X') flag=;
if (flag) mp[x][y]='X',DFS(dep+,x,y+),mp[x][y]='.';
}
int main()
{
bin[]=; for (int i=; i<=; i++) bin[i]=bin[i-]<<;
scanf("%d%d",&N,&M);
for (int i=; i<=N; i++) scanf("%s",mp[i]+);
DFS(,,);
printf("%d\n",(ANS+P)%P);
return ;
}

菜鸡.jpg

【BZOJ-2669】局部极小值 状压DP + 容斥原理的更多相关文章

  1. BZOJ2669 [cqoi2012]局部极小值 状压DP 容斥原理

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2669 题意概括 有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次.如果一个格子比所 ...

  2. BZOJ 2669 CQOI2012 局部极小值 状压dp+容斥原理

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2669 题意概述:实际上原题意很简洁了我就不写了吧.... 二话不说先观察一下性质,首先棋盘 ...

  3. 【uoj#37/bzoj3812】[清华集训2014]主旋律 状压dp+容斥原理

    题目描述 求一张有向图的强连通生成子图的数目对 $10^9+7$ 取模的结果. 题解 状压dp+容斥原理 设 $f[i]$ 表示点集 $i$ 强连通生成子图的数目,容易想到使用总方案数 $2^{sum ...

  4. 【bzoj2560】串珠子 状压dp+容斥原理

    题目描述 有 $n$ 个点,点 $i$ 和点 $j$ 之间可以连 $0\sim c_{i,j}$ 条无向边.求连成一张无向连通图的方案数模 $10^9+7$ .两个方案不同,当且仅当:存在点对 $(i ...

  5. BZOJ 2064: 分裂( 状压dp )

    n1+n2次一定可以满足..然后假如之前土地集合S1的子集subs1和之后土地集合S2的子集subs2相等的话...那么就少了2个+操作...所以最后答案就是n1+n2-少掉的最多操作数, 由状压dp ...

  6. 4455: [Zjoi2016]小星星|状压DP|容斥原理

    OrzSDOIR1ak的晨神 能够考虑状压DP枚举子集,求出仅仅保证连通性不保证一一相应的状态下的方案数,然后容斥一下就是终于的答案 #include<algorithm> #includ ...

  7. 【BZOJ 2669】 2669: [cqoi2012]局部极小值 (状压DP+容斥原理)

    2669: [cqoi2012]局部极小值 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 667  Solved: 350 Description 有一 ...

  8. bzoj2669 [cqoi2012]局部极小值 状压DP+容斥

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2669 题解 可以发现一个 \(4\times 7\) 的矩阵中,有局部最小值的点最多有 \(2 ...

  9. HDU5838 Mountain(状压DP + 容斥原理)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5838 Description Zhu found a map which is a N∗M ...

随机推荐

  1. GIT命令行的使用

    新手了解 有不对的地方指点下 首先, 了解下什么是GIT,GIT是一款开元的分布式版本控制工具, 在世界上的所有分布式版本控制工具中,GIT是最简单,最流行,同时也是最常用的 相比于其他版本的控制工具 ...

  2. [转]iOS开发中的火星坐标系及各种坐标系转换算法

     iOS开发中的火星坐标系及各种坐标系转换算法 源:https://my.oschina.net/u/2607703/blog/619183   其原理是这样的:保密局开发了一个系统,能将实际的坐标转 ...

  3. TCP三次握手建立连接

    基本过程:       ISN(初始序号)随时间变化,每一个连接具有不同的ISN,防止在网络延迟中分组被重新发送.   请求端发送SYN(同步序号 )=1,seq=ISN(32bits序号,每4ms+ ...

  4. Oracle数据库迁移

    1 在数据迁移时,用户首先有权限修改数据库,并且进行表空间创建.删除等权利 例如: select * from dba_tab_privs where grantee='SCOT'; ---查看SCO ...

  5. 缺陷管理平台mantis安装及配置

    软件说明:Mantis是一个基于PHP技术的轻量级的开源缺陷跟踪系统,以Web操作的形式提供项目管理及缺陷跟踪服务.在功能上.实用性上足以满足中小型项目的管理及跟踪.更重要的是其开源,不需要负担任何费 ...

  6. MogileFS系统简单配置实例

    实验原理: MogileFS是一个开源的分布式文件系统,用于组建分布式文件集群,由LiveJournal旗下DangaInteractive公司开发,Danga团队开发了包括 Memcached.Mo ...

  7. extjs学习资料

    ExtJs 入门教程 1.Extjs5.1.0教程云盘地址 http://pan.baidu.com/s/1qYhHiEw 2.Extjs3.x如下:   ExtJs 入门教程一[学习方法] ExtJ ...

  8. 报表工具如何实现多次导入Excel

    很多人在开发报表的时候会遇到将多张表样相同的excel导入到模板,然后提交至数据库中.但问题是很多情况,在线导入不支持一次性选择多个excel,一次只能选择一个excel,也不能将多个excel中的数 ...

  9. Java中的static关键字解析

    Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键 ...

  10. HDU 1729 Stone Game【SG函数】

    以下转载至:长春理工大学赵小舟博弈论ppt 题目大意: 1.有n个盒子,每个盒子都有它的容量s 2.在游戏开始时,每个盒子里都有一些石子 3.双方轮流进行游戏,向一个盒子投入n个石子,其中n不能大于当 ...