题目描述

有一个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. Deepin Linux下的Metasploit安装及优化

    前言 本文不限于Deepin Linux系统,类似的在ubuntu debian xubuntu等血统类似的Linux发行版中都可以使用这里方法来安装原生的metasploit 配置Kali Linu ...

  2. 【整理总结】Visual Studio 扩展和更新

    Add New File File Icons C# outline ClaudiaIDE Code alignment CodeMaid Indent Guides Inline Color Pic ...

  3. [并发并行]_[线程模型]_[Pthread线程使用模型之二 工作组work crew]

    Pthread线程使用模型之二工作组(Work crew) 场景 1.一些耗时的任务,比如分析多个类型的数据, 是独立的任务, 并不像 pipeline那样有序的依赖关系, 这时候pipeline就显 ...

  4. 【BZOJ3110】【LG3332】[ZJOI2013]K大数查询

    [BZOJ3110][LG3332][ZJOI2013]K大数查询 题面 洛谷 BZOJ 题解 和普通的整体分治差不多 用线段树维护一下每个查询区间内大于每次二分的值\(mid\)的值即可 然后再按套 ...

  5. Jenkins CLI 通过ssh方式链接时的证书

    在Jenkins自己的配置文档下,并没有详细说明要如何生成ssh证书,不过随便网上查一查就会有很多. 这里记录一个坑: 这个ssh必须要用ssh2!!! 这个ssh必须要用ssh2!!! 这个ssh必 ...

  6. XAF-如何修改内置的编辑器(Property Editor)

    本示例演示在web/win中给 日期选择控制显示出一个时钟及修改时间的控件.效果如下: 如果你装了XAF在这个路径中已经有了这个示例: %PUBLIC%\Documents\DevExpress De ...

  7. 2.5星|《哈佛商学院管理与MBA案例全书》:书名太唬人了,依据中文经管书汇编整理而成

    哈佛商学院管理与MBA案例全书(套装十册) 看到最后,列出的参考书目中全部是中文经管书,才明白这本书不是哈佛商学院出版的,是国内的编辑做的汇编.参考书目中除了中文经管书之外,还有一套<哈佛商学院 ...

  8. python编辑三级目录

    一.需求分析 三级目录要能够实现以下要求: 显示根目录,任何子目录中都可以通过输入b字符来返回根目录 任何子目录中都可以通过输入q字符来返回上一级目录 主目录进入子目录后,系统能够打印子目录,根据指打 ...

  9. ES6的新特性(8)——数组的扩展

    数组的扩展 扩展运算符 含义 扩展运算符(spread)是三个点(...).它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列. console.log(...[1, 2, 3]) / ...

  10. 欢迎来怼—第三次Scrum会议

    一.会议成员 队名:欢迎来怼队长:田继平队员:李圆圆,葛美义,王伟东,姜珊,邵朔,冉华小组照片: 二.会议时间 2017年10月15日    17:15-17:41   总用时26min 三.会议地点 ...