题目链接: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)

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std;
const int maxn=;
const int maxm=;
const int maxs=(<<)+;
const int mo=; int N,M,X,ans;
char mp[maxn][maxm];
struct XY{ int x,y; }p[];
int bin[],f[maxs][*+],cnt[maxs],vis[maxn][maxm],sz[maxs]; void data_in()
{
scanf("%d%d",&N,&M);
for(int i=;i<=N;i++){
scanf("%s",mp[i]+);
for(int j=;j<=M;j++)
if(mp[i][j]=='X') p[++X]=(XY){i,j};
}
for(int i=;i<=;i++) bin[i]=<<i-;
for(int s=;s<bin[];s++) sz[s]=sz[s>>]+(s&);
}
void dp(int tot)
{
for(int s=;s<bin[tot+];s++){
cnt[s]=;
memset(vis,,sizeof(vis));
for(int j=;j<=tot;j++) if(!(bin[j]&s)){
int x=p[j].x,y=p[j].y;
vis[x-][y-]=vis[x-][y]=vis[x-][y+]=
vis[x][y-]=vis[x][y]=vis[x][y+]=
vis[x+][y-]=vis[x+][y]=vis[x+][y+]=;
}
for(int i=;i<=N;i++)
for(int j=;j<=M;j++) cnt[s]+=-vis[i][j];
}
memset(f,,sizeof(f));
f[][]=;
for(int i=;i<=cnt[];i++)
f[][i]=f[][i-]*(cnt[]-i+)%mo;
for(int s=;s<bin[tot+];s++)
for(int i=sz[s];i<=cnt[s];i++){
f[s][i]=f[s][i-]*(cnt[s]-i+)%mo;
for(int j=;j<=tot;j++) if(bin[j]&s)
f[s][i]=(f[s][i]+f[s^bin[j]][i-])%mo;
}
}
bool check(int x,int y) { return mp[x-][y-]!='X'&&mp[x-][y]!='X'&&mp[x-][y+]!='X'&&mp[x][y-]!='X'; }
void dfs(int x,int y,int n)
{
if(x>N){
dp(X+n);
if(n%==) ans=(ans+f[bin[X+n+]-][N*M])%mo;
else ans=(ans-f[bin[X+n+]-][N*M]+mo)%mo;
return;
}
int xx=x,yy=y+;
if(yy>M) xx++,yy=;
if(mp[x][y]=='X'){
if(check(x,y)) dfs(xx,yy,n);
}
else{
if(check(x,y)){
mp[x][y]='X',p[X+n+]=(XY){x,y};
dfs(xx,yy,n+);
mp[x][y]='.';
}
dfs(xx,yy,n);
}
}
void work()
{
dfs(,,);
printf("%d\n",ans);
}
int main()
{
data_in();
work();
return ;
}

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. Struts2 第六讲 -- Struts2的结果类型

    7.struts2的结果类型 l 每个 action 方法都将返回一个 String 类型的值, Struts 将根据这个值来决定响应什么结果. l 每个 Action 声明都必须包含有数量足够多的 ...

  2. Struts2 第一讲 -- Struts2开发前奏

    我们在学习Struts之前,先来复习一下Servlet,众所周知Servlet是JavaWeb的三大组件.我们发送一个请求,这个请求交给Servlet处理,Servlet将处理的结果返还给浏览器.每个 ...

  3. ios应用数据存储方式(偏好设置)-转

    一.简单介绍 1.很多ios应用都支持偏好设置,比如保存用户名,密码,字体大小等设置,ios提供了一套标准的解决方案来为应用加入偏好设置功能. 2.每个应用都有个NSUserDefaults实例,通过 ...

  4. django-auth认证模块

    ########django-auth认证模块######## auth模块:它是django自带的用户认证模块,帮我们解决了登陆,注册,注销,修改密码 等等一系列的操作,封装成一个个方法,方便我们使 ...

  5. multimap的使用

    multimap由于允许有重复的元素,所以元素插入.删除.查找都与map不同. 插入insert(pair<a,b>(value1,value2)) #include <iostre ...

  6. motto - MySQL - 常用命令

    本文搜索关键字:motto mysql 登录数据库 mysql -uroot -proot -P3306 -h127.0.0.1 --prompt "\u@\h \d>" - ...

  7. 全盘解决eclipse之maven项目报错

    每次新建maven的web(war包方式)项目时都会报错而且都要手动改,很麻烦 解决:(注意里面的jdk版本换成自己的) 改变maven配置文件   settings.xml 在文件的<prof ...

  8. Linux centos7 安装python3 及 GCC

    1.用wget下载python源码 PYTHON下载 找适合自己的版本,我下载的是3.7.2 2.用tar命令解压下载的文件 tar -zxvf Python-3.7.2.tgz 3.进入目录解压后的 ...

  9. Flask之endpoint错误View function mapping is overwriting an existing endpoint function: ***

    最近在学习Flask, 其中遇到了一个错误, 发现这个问题和Flask, 路由有关系, 所以就记了下来 错误代码: from flask import Flask, render_template, ...

  10. C# 用HttpWebRequest模拟一个虚假的IP伪造ip

    有人会说:IP验证是在TCP层完成的,不是HTTP层完成的,如果伪造IP的话可能连TCP的三次握手都完不成.我这里说的不是完全意义的伪造.如果你使用透明代理上网,那么在透明代理发送给服务器端的HTTP ...