题目描述

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

输入

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

输出

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

样例输入

3 2
X.
..
.X

样例输出

60


题解

容斥原理+状压dp

“给出所有局部极小值的位置” 有两层含义:
1.给出的位置是局部最小值;
2.非给出的位置不是局部最小值。

先考虑第一层含义怎么做:

我们把数从小到大填入矩阵中,那么如果一个格子是局部最小值且没有填入数,那么它周围的数都不能填。除此之外的位置均可选择。

因此设 $f[i][j]$ 表示填入前 $i$ 个数,局部最小值的填入情况为 $j$ 的方案数。

那么对于 $f[i][j]$ ,有两种转移:
不填局部最小值的位置,那么 $f[i][j]=f[i-1][j]+可以填的位置数$ 。我们预处理每种局部最小值填入情况下可以填入多少个数 $v[j]$,之后就能算出可以填的位置数 $v[j]-i+1$ 。
填局部最小值的位置,那么枚举填入了第 $k$ 个局部最小值,有 $f[i][j]=f[i-1][j-2^k]$ 。

最终 $f[nm][2^{局部最小值个数}-1]$ 即为答案。

再考虑第二层含义:

考虑容斥,那么讨论其它位置为局部最小值的情况,同样的方法进行dp,乘以容斥系数 $(-1)^{多填的位置数}$ 累计到答案中即可。

注意判断无解的情况。

由于容斥过程时刻要求一个局部最小值的八连通位置不能存在局部最小值,因此状态数是很小的。

时间复杂度 $O(跑得飞快)$

#include <cstdio>
#include <cstring>
#include <algorithm>
#define mod 12345678
using namespace std;
const int dx[] = {0 , 1 , 1 , 1 , 0 , -1 , -1 , -1 , 0} , dy[] = {0 , 1 , 0 , -1 , -1 , -1 , 0 , 1 , 1};
char str[10];
int n , m , px[30] , py[30] , p , vis[6][10] , filled[6][10] , v[260] , f[30][260];
int solve()
{
int i , j , k;
memset(v , 0 , sizeof(v));
for(i = 0 ; i < (1 << p) ; i ++ )
{
memset(vis , 0 , sizeof(vis));
for(j = 0 ; j < p ; j ++ )
if(!(i & (1 << j)))
for(k = 0 ; k < 9 ; k ++ )
vis[px[j] + dx[k]][py[j] + dy[k]] = 1;
for(j = 1 ; j <= n ; j ++ )
for(k = 1 ; k <= m ; k ++ )
v[i] += !vis[j][k];
}
memset(f , 0 , sizeof(f));
f[0][0] = 1;
for(i = 1 ; i <= n * m ; i ++ )
{
for(j = 0 ; j < (1 << p) ; j ++ )
{
if(v[j] >= i) f[i][j] = f[i - 1][j] * (v[j] - i + 1) % mod;
for(k = 0 ; k < p ; k ++ )
if(j & (1 << k))
f[i][j] = (f[i][j] + f[i - 1][j ^ (1 << k)]) % mod;
}
}
return f[n * m][(1 << p) - 1];
}
int dfs(int x , int y)
{
if(y > m) x ++ , y = 1;
if(x > n) return solve();
int i , ans = dfs(x , y + 1);
for(i = 0 ; i < 9 ; i ++ )
if(filled[x + dx[i]][y + dy[i]])
break;
if(i == 9)
{
px[p] = x , py[p ++ ] = y , filled[x][y] = 1;
ans = (ans - dfs(x , y + 1) + mod) % mod;
p -- , filled[x][y] = 0;
}
return ans;
}
int main()
{
int i , j;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= n ; i ++ )
{
scanf("%s" , str + 1);
for(j = 1 ; j <= m ; j ++ )
if(str[j] == 'X')
px[p] = i , py[p ++ ] = j;
}
for(i = 0 ; i < p ; i ++ )
{
for(j = 0 ; j < i ; j ++ )
{
if(abs(px[i] - px[j]) <= 1 && abs(py[i] - py[j]) <= 1)
{
puts("0");
return 0;
}
}
filled[px[i]][py[i]] = 1;
}
printf("%d\n" , dfs(1 , 1));
return 0;
}

【bzoj2669】[cqoi2012]局部极小值 容斥原理+状压dp的更多相关文章

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

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

  2. HDU 4336 容斥原理 || 状压DP

    状压DP :F(S)=Sum*F(S)+p(x1)*F(S^(1<<x1))+p(x2)*F(S^(1<<x2))...+1; F(S)表示取状态为S的牌的期望次数,Sum表示 ...

  3. #186 path(容斥原理+状压dp+NTT)

    首先只有一份图时显然可以状压dp,即f[S][i]表示S子集的哈密顿路以i为终点的方案数,枚举下个点转移. 考虑容斥,我们枚举至少有多少条原图中存在的边(即不合法边)被选进了哈密顿路,统计出这个情况下 ...

  4. [LuoguP2167][SDOI2009]Bill的挑战_容斥原理/状压dp

    Bill的挑战 题目链接:https://www.luogu.org/problem/P2167 数据范围:略. 题解: 因为$k$特别小,想到状压. 状压的方式也非常简单,就是暴力枚举. 但是会不会 ...

  5. bzoj 3812: 主旋律 [容斥原理 状压DP]

    3812: 主旋律 题意:一张有向图,求它的生成子图是强连通图的个数.\(n \le 15\) 先说一个比较暴力的做法. 终于知道n个点图的是DAG的生成子图个数怎么求了. 暴力枚举哪些点是一个scc ...

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

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

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

    2669: [cqoi2012]局部极小值 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 774  Solved: 411[Submit][Status ...

  8. 洛谷$P$3160 局部极小值 $[CQOI2012]$ 状压$dp$

    正解:状压$dp$ 解题报告: 传送门! 什么神仙题昂,,,反正我是没有想到$dp$的呢$kk$,,,还是太菜了$QAQ$ 首先看数据范围,一个4×7的方格,不难想到最多有8个局部极小值,过于显然懒得 ...

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

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

随机推荐

  1. 20155327李百乾 Exp3 免杀原理与实践

    20155327李百乾 Exp3 免杀原理与实践 实践guocheng 一.Msfvenom使用编码器 1.利用(virustota)[https://www.virustotal.com/]检测实验 ...

  2. 【转载】从零实现3D图像引擎:(2)画2D直线不简单

    原文:从零实现3D图像引擎:(2)画2D直线不简单 1. 数学分析 1) 画直线的问题 本来我以为画直线会很容易,随便拿个直线公式,遍历X求Y画出来不就完了么,但事实并非如此.以2D直线为例,因为3D ...

  3. 【LG3835】可持久化平衡树

    [LG3835]可持久化平衡树 题面 洛谷 解法一 参考文章 rope大法好 \(rope\)基本操作: #include<ext/rope> using namespace __gnu_ ...

  4. GlusterFS学习之路(二)GlusterFS部署及卷类型使用

    一.环境说明 主机名 IP地址 角色 磁盘 gluster-node1 192.168.56.11 Server.Client /dev/sdb./dev/sdc./dev/sdd gluster-n ...

  5. 两个字段联合约束(mysql)

    联合约束:ALTER TABLE `lywl_provider_package` ADD unique(providerId,packCode) 给一个表建唯一约束

  6. 对posintion属性的简单认识,对于还在纠结的同学们,有一定的帮助

      position的四个属性值: relative ,absolute ,fixed,static 下面分别讲述这四个属性,以简单代码表示 <div id="parent" ...

  7. Vue.js之常用指令

    vue常用指令 vue.js官方给自己的定义是数据模板引擎,并给出了一套渲染数据的指令.本文详细介绍vue.js的常用指令. 官网:点我 一.v-text.v-html v-text:用于绑定文本 v ...

  8. php常用的几个预定义变量

    __FILE__:返回所在路径文件名和文件名称 __DIR__:返回文件所在的完整目录 __LINE__:返回当前文件代码的行号 __CLASS__:返回当前类名 __FUNCTION__:返回当前方 ...

  9. 初探C#

    初探.NET底层原理 学习C#离不开.net平台,因为微软的开发平台真的是太强大了,它为每一个开发者都做了太多太多,但是我们不仅要知道怎么用,而且也应该知道其中的内部到底包含了什么.本篇文章不仅讲一些 ...

  10. Method 'ExecuteAsync' in type 'System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy' does not have an implementation

    一.错误信息 Entity Framework 6.0数据迁移:Add-Migration XXXX 命令发生错误 System.Reflection.TargetInvocationExceptio ...