题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2669

题意概述:实际上原题意很简洁了我就不写了吧。。。。

二话不说先观察一下性质,首先棋盘很窄,可以乱搞的样子,然后注意到如果一个点是局部极小值那么周围3*3矩阵内不能有另一个局部最小值。于是画个图发现题目的数据范围最多有8个局部最小值。性质大概就是这些了。

暴力实际上是搜索,本质是多阶段决策问题。由于棋盘很小,容易让人联想到搞个插头dp之类东西来弄一下,依次填每个格子来作为一个决策阶段。然后就发现。。。这个东西太复杂了。。。等你想出来不知道什么时候去了(而且很有可能想不出来)。。。于是需要换个思路,把决策阶段改一下,每一行作为阶段的话更加复杂。。。弃疗。那么决策阶段很有可能就不是按照格子的顺序来的了。注意到局部最小值一定是周围的格子里面最小的那个,并且最多只有8个局部最小值,那么尝试从小到大填充每一个数字作为阶段,把局部最小值是否填充的状态压进去。

于是令f(s,i)表示用1~i的数字填充棋盘,集合s中的局部最小值已经被填充的方案数。

分析这种决策下的性质,发现一个局部最小值一定是以其为中心3*3内最先填的那个,也就是说如果一个局部最小值没有填充,那么周围3*3的点都不能填充。排除所有不可以填充的点剩下的就是可以填充的点,令cnt[s]表示局部极小值填充状态为s时的棋盘上最多有几个数字。

得到f(s,i)=f(s,i-1)*C(cnt[s]-i+1,1)+sum{ f(s-{j},i-1) | j是s的子集 },时间复杂度O(N*M*X*2^X),X表示棋盘上有多少个局部极小值。

但是可以注意到在状态设计的时候可以保证题目给出的X都成为局部最小值,但是可能让不是局部最小值的位置变成局部最小值。

于是这题最神的地方来了:容斥!由于棋盘很小,所以说打个回溯跑一下局部极小值的分布位置发现最多也就16000多的方案。我们用回溯跑出每一种题目要求位置为局部极小值的棋盘状态,对于每个状态来一次dp,然后根据有多少个额外的点是局部极小值进行奇偶容斥就得出答案。

时间复杂度O(O(容斥)*N*M*X*2^X)

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cstdlib>
  5. #include<algorithm>
  6. #include<cmath>
  7. #include<queue>
  8. #include<set>
  9. #include<map>
  10. #include<vector>
  11. #include<cctype>
  12. using namespace std;
  13. const int maxn=;
  14. const int maxm=;
  15. const int maxs=(<<)+;
  16. const int mo=;
  17. int N,M,X,ans;
  18. char mp[maxn][maxm];
  19. struct XY{ int x,y; }p[];
  20. int bin[],f[maxs][*+],cnt[maxs],vis[maxn][maxm],sz[maxs];
  21. void data_in()
  22. {
  23. scanf("%d%d",&N,&M);
  24. for(int i=;i<=N;i++){
  25. scanf("%s",mp[i]+);
  26. for(int j=;j<=M;j++)
  27. if(mp[i][j]=='X') p[++X]=(XY){i,j};
  28. }
  29. for(int i=;i<=;i++) bin[i]=<<i-;
  30. for(int s=;s<bin[];s++) sz[s]=sz[s>>]+(s&);
  31. }
  32. void dp(int tot)
  33. {
  34. for(int s=;s<bin[tot+];s++){
  35. cnt[s]=;
  36. memset(vis,,sizeof(vis));
  37. for(int j=;j<=tot;j++) if(!(bin[j]&s)){
  38. int x=p[j].x,y=p[j].y;
  39. vis[x-][y-]=vis[x-][y]=vis[x-][y+]=
  40. vis[x][y-]=vis[x][y]=vis[x][y+]=
  41. vis[x+][y-]=vis[x+][y]=vis[x+][y+]=;
  42. }
  43. for(int i=;i<=N;i++)
  44. for(int j=;j<=M;j++) cnt[s]+=-vis[i][j];
  45. }
  46. memset(f,,sizeof(f));
  47. f[][]=;
  48. for(int i=;i<=cnt[];i++)
  49. f[][i]=f[][i-]*(cnt[]-i+)%mo;
  50. for(int s=;s<bin[tot+];s++)
  51. for(int i=sz[s];i<=cnt[s];i++){
  52. f[s][i]=f[s][i-]*(cnt[s]-i+)%mo;
  53. for(int j=;j<=tot;j++) if(bin[j]&s)
  54. f[s][i]=(f[s][i]+f[s^bin[j]][i-])%mo;
  55. }
  56. }
  57. bool check(int x,int y) { return mp[x-][y-]!='X'&&mp[x-][y]!='X'&&mp[x-][y+]!='X'&&mp[x][y-]!='X'; }
  58. void dfs(int x,int y,int n)
  59. {
  60. if(x>N){
  61. dp(X+n);
  62. if(n%==) ans=(ans+f[bin[X+n+]-][N*M])%mo;
  63. else ans=(ans-f[bin[X+n+]-][N*M]+mo)%mo;
  64. return;
  65. }
  66. int xx=x,yy=y+;
  67. if(yy>M) xx++,yy=;
  68. if(mp[x][y]=='X'){
  69. if(check(x,y)) dfs(xx,yy,n);
  70. }
  71. else{
  72. if(check(x,y)){
  73. mp[x][y]='X',p[X+n+]=(XY){x,y};
  74. dfs(xx,yy,n+);
  75. mp[x][y]='.';
  76. }
  77. dfs(xx,yy,n);
  78. }
  79. }
  80. void work()
  81. {
  82. dfs(,,);
  83. printf("%d\n",ans);
  84. }
  85. int main()
  86. {
  87. data_in();
  88. work();
  89. return ;
  90. }

BZOJ 2669 CQOI2012 局部极小值 状压dp+容斥原理的更多相关文章

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

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

  2. bzoj 2669 题解(状压dp+搜索+容斥原理)

    这题太难了...看了30篇题解才整明白到底咋回事... 核心思想:状压dp+搜索+容斥 首先我们分析一下,对于一个4*7的棋盘,低点的个数至多只有8个(可以数一数) 这样的话,我们可以进行一个状压,把 ...

  3. 【BZOJ-2669】局部极小值 状压DP + 容斥原理

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

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

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

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

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

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

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

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

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

  8. bzoj 2669 [cqoi2012]局部极小值 DP+容斥

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

  9. BZOJ 2560: 串珠子 (状压DP+枚举子集补集+容斥)

    (Noip提高组及以下),有意者请联系Lydsy2012@163.com,仅限教师及家长用户. 2560: 串珠子 Time Limit: 10 Sec Memory Limit: 128 MB Su ...

随机推荐

  1. 使用带有对象的data-ng-bind

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  2. Mysql jar包

    密码cngb https://pan.baidu.com/share/init?surl=bSGA6T-LTwjx-qaNAiipCA

  3. NSDictionary+JSON - iOS

    日常开发中常用的一个相互转换的方法; 直接创建对应的类,引用如下方法即可实现; 具体 code 如下: 声明: #import <Foundation/Foundation.h> @int ...

  4. 修改状态栏,电池,wifi的颜色为白色

    修改状态栏,电池,wifi的颜色为白色 在info里面设置View controller-based status bar appearance,为no

  5. 【2018 ICPC焦作网络赛 K】Transport Ship(多重背包二进制优化)

    There are N different kinds of transport ships on the port. The ith kind of ship can carry the weigh ...

  6. <CPP学习>第一天 第一个CPP程序 hello word

    由于我是计算机类嵌入式专业的大一学生,之前一直使用的是生万物的C语言,了解了其过程性语言的特性及其基础语法,在大一下学期期末阶段想自学一下C++,其实在开学初就买了一本C++ Primer,但由于各种 ...

  7. 在mac上显示网速的软件——iStat Menus 5:

    在mac上显示网速的软件——iStat Menus 5: https://bjango.com/mac/istatmenus/ 注册码: Email: 982092332@qq.com SN: GAW ...

  8. LintCode 12.带最小值操作的栈(两种方法实现)

    题目描述 实现一个带有取最小值min方法的栈,min方法将返回当前栈中的最小值. 你实现的栈将支持push,pop 和 min 操作,所有操作要求都在O(1)时间内完成. 样例 如下操作:push(1 ...

  9. python运算符及优先级顺序

    python语言是一门脚本语言,支持面向对象.面向过程编程,兼具编译性和解释性的动态语言,整理出学习过程中一些基本Python运算符和运算符的优先级顺序. 一.算术运算符 运算符 描述 + 加 - 两 ...

  10. npm install 报错

    今天准备在服务器上部署一下pm2,发现 npm install -g pm2   爆出了错误 error Unexpected end of JSON input while parsing near ...