题目描述

有一个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. # 20155337 2016-2017-2 《Java程序设计》第十周学习总结

    20155337 2016-2017-2 <Java程序设计>第十周学习总结 教材学习内容总结 网络编程 •网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据.程序员所作的事情就 ...

  2. banwagon vps装wordpress

    http://www.banwagong.com/213.html http://www.banwagong.com/225.html http://www.banwagong.com/230.htm ...

  3. PhoneGap3.2安装步骤

    1.首选安装好JDK.Android SDK.Ant 配置如下:        系统环境变量        ANDROID_HOME Value: C:\Development\adt-bundle\ ...

  4. 关于快速沃尔什变换(FWT)的一些个人理解

    定义 FWT是一种快速完成集合卷积运算的算法. 它可以用于求解类似 $C[i]=\sum\limits_{j⊗k=i}A[j]*B[k]$ 的问题. 其中⊗代表位运算中的|,&,^的其中一种. ...

  5. SRM 698 div1 RepeatString

    250pts RepeatString 题意:问最少修改多少次将一个字符串修改为AA的形式.可以插入一个字符,删除一个字符,修改字符. 思路:枚举分界点,然后dp一下. /* * @Author: m ...

  6. 解决 mysql in 查询排序问题

    select id,title from za_item where -- id ,) 返回的结果第一条是对应id是1000,第二条是1003. 如果我们想让结果和in里面的排序一致,可以这么做. s ...

  7. idea alt+enter导包时被锁定导某一个包时的解决方法

    在只有一个包指向的时候,把光标放在Test这种字符之间的话 就会直接导这个 所以把光标放在最后就可以导别的了

  8. javaweb(三十八)——mysql事务和锁InnoDB(扩展)

    MySQL/InnoDB的加锁分析,一直是一个比较困难的话题.我在工作过程中,经常会有同事咨询这方面的问题.同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题.本文,准备就My ...

  9. MES与ERP的区别(转)

    MES和ERP有很大的不同,主要体现在以下几个方面: 1.管理的目标不同 ERP的重点在于财务,也就是从财务的角度出发来对企业的资源进行计划,相关的模块也是以财务为核心的展开,最终的管理数据也是集中到 ...

  10. 车架号识别,VIN码识别 助力汽车后市场

    又有一家汽配圈新贵引入了小译家的 车架号识别(VIN码识别)技术 那就是明觉科技 是一个服务于汽车后市场 集数据服务.行业数据挖掘 及“互联网+”为一体的汽配信息协作平台 旗下拥有一款全车零配件信息智 ...