题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=2669

题解:

容斥,DP,DFS

先看看 dp 部分:
首先呢,X的个数不会超过 8个
个数很少,所以考虑状压,把需要填 X的那几个位置状压为二进制10表示对应的那个X位置是否已经填数。
同时填的数互不重复,考虑从小填到大。
cnt[S] 表示除了不在集合 S 里的 X 位置及其周围的位置,剩下的位置个数
定义 dp[i][S]表示从小到大填数填完了i这个数,且已经填了的 S 这个集合里的 X 位置的方案数
转移:依次去填数 1~N*M,每次有两种选择:
1).把这个数填在 某个 X 位置(枚举一个 k表示第 k个 X 位置填当前数)
dp[i][S]+=dp[i-1][S^(1<<(k-1))]

2).把这个数填在非 X 位置,那么填的位置有 cnt[S]-(i-1) 种。
dp[i][s]+=dp[i-1][s]*(cnt[s]-(i-1)) (好好理解一下这个转移)

这样 dp 可以保证那些给出的 X 位置一定是局部最小值,
因为第二种转移的填数位置都不能填在还没有填数的 X 位置的周围。
所以就完了么?
当然还没有,尽管我们保证了给出的 X 位置一定是局部最小值,
但是没有保证非 X位置一定不是非局部最小值。即,求出来的 dp[N*M][all_S(全集)]的意思是至少all_S集合里的 X位置为局部最小值的方案数
所以容斥如下:
ANS = 至少多填了0个局部最小值的方案数(dp[N*M][all_S])
          -至少多填了1个局部最小值的方案数
         +至少多填了2个局部最小值的方案数
          -....+ ....
这些用于容斥的方案数的求法:
DFS 搜索出哪些非 X 位置还可以改为 X ,
然后对于每一种新的填法,去跑一遍上述的dp即可求得对应的方案数。

代码:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #define _ % mod
  5. #define filein(x) freopen(#x".in","r",stdin);
  6. #define fileout(x) freopen(#x".out","w",stdout);
  7. using namespace std;
  8. const int mv[9][2]={{0,0},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
  9. const int mod=12345678;
  10. char mp[10][10];
  11. int N,M,ANS;
  12. int solve(){
  13. static bool vis[10][10];
  14. static int dp[30][1<<8],cnt[1<<8],x[10],y[10],tot,tmp;
  15. tot=0; memset(dp,0,sizeof(dp));
  16. for(int i=1;i<=N;i++)
  17. for(int j=1;j<=M;j++) if(mp[i][j]=='X')
  18. tot++,x[tot]=i,y[tot]=j;
  19. for(int s=0;s<1<<tot;s++){
  20. tmp=0; memset(vis,0,sizeof(vis));
  21. for(int i=1;i<=tot;i++) if(!(s&(1<<(i-1))))
  22. for(int k=0;k<9;k++)
  23. vis[x[i]+mv[k][0]][y[i]+mv[k][1]]=1;
  24. for(int i=1;i<=N;i++)
  25. for(int j=1;j<=M;j++)
  26. if(!vis[i][j]) tmp++;
  27. cnt[s]=tmp;
  28. }
  29. dp[0][0]=1;
  30. for(int i=1;i<=N*M;i++)
  31. for(int s=0;s<1<<tot;s++){
  32. dp[i][s]=(1ll*dp[i][s]+1ll*dp[i-1][s]*max(cnt[s]-(i-1),0)_)_;
  33. for(int k=1;k<=tot;k++) if(s&(1<<(k-1)))
  34. dp[i][s]=(1ll*dp[i][s]+dp[i-1][s^(1<<(k-1))])_;
  35. }
  36. return dp[N*M][(1<<tot)-1];
  37. }
  38. void dfs(int x,int y,int t){
  39. if(y==M+1){dfs(x+1,1,t);return;}
  40. if(x==N+1){
  41. int tmp=solve();
  42. if(t&1) tmp=(-1ll*tmp+mod)_;
  43. ANS=((1ll*ANS+tmp)_+mod)_;
  44. return;
  45. }
  46. dfs(x,y+1,t);
  47. bool fg=1;
  48. for(int k=0;k<9;k++)
  49. if(mp[x+mv[k][0]][y+mv[k][1]]=='X') fg=0;
  50. if(fg){
  51. mp[x][y]='X';
  52. dfs(x,y+1,t+1);
  53. mp[x][y]='.';
  54. }
  55. }
  56. int main()
  57. {
  58. scanf("%d%d",&N,&M);
  59. for(int i=1;i<=N;i++)
  60. scanf("%s",mp[i]+1);
  61. dfs(1,1,0);
  62. printf("%d",ANS);
  63. return 0;
  64. }

●BZOJ 2669 [cqoi2012]局部极小值的更多相关文章

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

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

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

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

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

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

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

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

  5. [BZOJ2669] [cqoi2012]局部极小值

    [BZOJ2669] [cqoi2012]局部极小值 Description 有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次.如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点) ...

  6. P3160 [CQOI2012]局部极小值

    题目 P3160 [CQOI2012]局部极小值 一眼就是状压,接下来就不知道了\(qwq\) 做法 我们能手玩出局部小值最多差不多是\(8,9\)个的样子,\(dp_{i,j}\)为填满\(1~i\ ...

  7. P3160 [CQOI2012]局部极小值 题解(状压DP+容斥)

    题目链接 P3160 [CQOI2012]局部极小值 双倍经验,双倍快乐 解题思路 存下来每个坑(极小值点)的位置,以这个序号进行状态压缩. 显然,\(4*7\)的数据范围让极小值点在8个以内(以下示 ...

  8. BZOJ 2669 Luogu P3160 [CQOI2012]局部极小值 (容斥原理、DP)

    题目链接 (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=2669 (luogu) https://www.luogu.org/prob ...

  9. BZOJ 2669 【CQOI2012】 局部极小值

    题目链接:局部极小值 这是一道\(dp\)好题. 由于需要保证某些位置比周围都要小,那么我们可以从小到大把每个数依次填入,保证每个局部极小值填入之前周围都不能填,就只需要在加入的时候计数了. 由于局部 ...

随机推荐

  1. linux 50个常用命令

    1.ls命令 ls是list的缩写,常用命令为ls(显示出当前目录列表),ls -l(详细显示当前目录列表),ls -lh(人性化的详细显示当前目录列表),ls -a(显示出当前目录列表,包含隐藏文件 ...

  2. XML使用练习

    #!/usr/bin/env python # -*- coding:utf-8 -*- import requests from xml.etree import ElementTree as ET ...

  3. 微信小程序轮播图

    swiper标签 <!--index.wxml--> <swiper class="swiper" indicator-dots="true" ...

  4. 直方图均衡化及matlab实现

    在处理图像时,偶尔会碰到图像的灰度级别集中在某个小范围内的问题,这时候图像很难看清楚.比如下图: 它的灰度级别,我们利用一个直方图可以看出来(横坐标从0到255,表示灰度级别,纵坐标表示每个灰度级别的 ...

  5. nyoj 星期几?

    星期几? 时间限制:500 ms  |  内存限制:65535 KB 难度:2   描述                      Acmer 小鱼儿 埋头ku算一道题 条件:已知给定 一日期 告诉你 ...

  6. java 1.7新特性

    try( ... ){ ... } catch(xxx e){ ... } java1.7特性,叫做try-with-resource,实现了AutoCloseable接口的实例可以放在try(... ...

  7. HDFS文件读写操作(基础基础超基础)

    环境 OS: Ubuntu 16.04 64-Bit JDK: 1.7.0_80 64-Bit Hadoop: 2.6.5 原理 <权威指南>有两张图,下次po上来好好聊一下 实测 读操作 ...

  8. svn介绍和安装

      什么是SVN呢,作用是什么: SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS/CVS,它采取了分支管理系统,它的设计目标就是取代CVS.SVN就是用于多个人共同开 ...

  9. WKWebView使用

    WKWebView比之之前使用的UIWebView更加具有优势,UIWebView更加的笨重,UIWebView占用更多的内存,且内存的峰值更加的夸张,WKWebView加载的速度也更快,而且其更多的 ...

  10. Python django实现简单的邮件系统发送邮件功能

    Python django实现简单的邮件系统发送邮件功能 本文实例讲述了Python django实现简单的邮件系统发送邮件功能. django邮件系统 Django发送邮件官方中文文档 总结如下: ...