题链:

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即可求得对应的方案数。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define _ % mod
#define filein(x) freopen(#x".in","r",stdin);
#define fileout(x) freopen(#x".out","w",stdout);
using namespace std;
const int mv[9][2]={{0,0},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
const int mod=12345678;
char mp[10][10];
int N,M,ANS;
int solve(){
static bool vis[10][10];
static int dp[30][1<<8],cnt[1<<8],x[10],y[10],tot,tmp;
tot=0; memset(dp,0,sizeof(dp));
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++) if(mp[i][j]=='X')
tot++,x[tot]=i,y[tot]=j;
for(int s=0;s<1<<tot;s++){
tmp=0; memset(vis,0,sizeof(vis));
for(int i=1;i<=tot;i++) if(!(s&(1<<(i-1))))
for(int k=0;k<9;k++)
vis[x[i]+mv[k][0]][y[i]+mv[k][1]]=1;
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
if(!vis[i][j]) tmp++;
cnt[s]=tmp;
}
dp[0][0]=1;
for(int i=1;i<=N*M;i++)
for(int s=0;s<1<<tot;s++){
dp[i][s]=(1ll*dp[i][s]+1ll*dp[i-1][s]*max(cnt[s]-(i-1),0)_)_;
for(int k=1;k<=tot;k++) if(s&(1<<(k-1)))
dp[i][s]=(1ll*dp[i][s]+dp[i-1][s^(1<<(k-1))])_;
}
return dp[N*M][(1<<tot)-1];
}
void dfs(int x,int y,int t){
if(y==M+1){dfs(x+1,1,t);return;}
if(x==N+1){
int tmp=solve();
if(t&1) tmp=(-1ll*tmp+mod)_;
ANS=((1ll*ANS+tmp)_+mod)_;
return;
}
dfs(x,y+1,t);
bool fg=1;
for(int k=0;k<9;k++)
if(mp[x+mv[k][0]][y+mv[k][1]]=='X') fg=0;
if(fg){
mp[x][y]='X';
dfs(x,y+1,t+1);
mp[x][y]='.';
}
}
int main()
{
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++)
scanf("%s",mp[i]+1);
dfs(1,1,0);
printf("%d",ANS);
return 0;
}

●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. python 闭包计算移动均值及nonlocal的使用

    class Averager1(): '''计算移动平均值的类第一种写法''' def __init__(self): self.series = [] def __call__(self,new_v ...

  2. initializer element is not a compile-time constant

    初始化一个全局变量或static变量时,只能用常量赋值,不能用变量赋值! 如下就会报这个错误(KUIScreenWidth)是变量 static CGFloat const topButtonWidt ...

  3. Windows Server2012 故障转移集群之动态仲裁(Dynamic Quorum)

    本篇文章主要介绍Windows2012的故障转移集群一个新功能“动态仲裁”,默认该功能是开启的: 动态仲裁能在当前群集投票出现分歧的情况下取消某些节点的投票权限,比如偶数个节点的群集环境.仲裁见证和动 ...

  4. JAVA_SE基础——12.运算符的优先级

    优先级 操作符 含义 关联性 用法 ---------------------------------------------------------------- 1 [ ] 数组下标 左 arra ...

  5. Mysql必须知道的知识

    最近在准备面试,所以也整理了一些Mysql数据库常用的知识,供大家参考. 1.MySQL的复制原理以及流程 (1).复制基本原理流程 1. 主:binlog线程--记录下所有改变了数据库数据的语句,放 ...

  6. Python模块configparser(操作配置文件ini)

    configparser模块提供对ini文件的增删改查方法. ini文件的数据格式: [name1] attribute1=value1 attribute2=value2 [name2] attri ...

  7. redis 持久化之 RDB

    redis的运维过程中,我们对数据持久化做一个基本的总结. 1什么是持久化: redis 所有数据保持在内存中,对数据的更新将异步地保存到磁盘上. RDB 文件创建的过程是直接从内存 写入到我们我磁盘 ...

  8. xftp上传文件失败,执行程序发现磁盘满了:No space left on device

    参考链接 No space left on device 解决Linux系统磁盘空间满的办法http://www.cnblogs.com/aspirant/p/3604801.html如何解决linu ...

  9. golang微信公众号请求获取信息

    初次用golang在公众号中获取信息,记录一下 看了下文档,粗略的写了个demo,如下: func HttpGet(c*gin.Context) { var param GetType if er:= ...

  10. Hibernate(四):Hello World

    下载hibernate开发包: 在本章之前需要继承hibernate开发插件到eclipse,详细操作请参考我的博文:<Hibernate(一):安装hibernate插件到eclipse环境& ...