bzoj 2669 题解(状压dp+搜索+容斥原理)
这题太难了...看了30篇题解才整明白到底咋回事...
核心思想:状压dp+搜索+容斥
首先我们分析一下,对于一个4*7的棋盘,低点的个数至多只有8个(可以数一数)
这样的话,我们可以进行一个状压,把所有的低点压进来
然后我们从小到大枚举所有数,转移即可
记状态f[i][j]表示到了第i个数,低点的状态为j的方案数
那么在转移的时候,有两个转移方向:
①.如果第i个数放在低点上,那么我们可以枚举所有的低点k,如果低点没有在状态里,有:
dp[i][j|(1<<k)]+=dp[i-1][j]
②.如果第i个数放在高点上,那么我们需要枚举所有可以使用的高点,所谓可以使用的高点就是指的某一高点周围没有未使用的低点(原因:我是从小往大枚举的所有数,如果我在一个高点上放了一个数而他附近却有低点没有放上,那么这个低点会变得比这个高点高,这就是不合法的了。)
但是如果每次都枚举,时间复杂度是会爆炸的,所以我们需要进行一个预处理num[i],表示i状态下有多少个高点可以使用
最后的答案就是dp[n*m][1<<cnt-1]
可是这个答案是正确的吗?
我们发现,如果仅仅是这么枚举,很容易出现一种情况:某个点本来是高点,但是由于随意的放置使得这个点变成了低点
所以我们需要解决掉这个问题
怎么解决?
很显然,我们只需求出把每个可能被放错的高点真正作为低点的方案数,然后用总方案数减掉这个方案数就可以了。
可是,如果我们分别去减,由于减的方案数还要像上面那样dp出来,所以会产生更多的重复(即高点1和高点2同时放错)
所以我们需要利用容斥,即
0个高点反转-1个高点反转+2个高点反转....
(反转指反转状态)
那么怎么反转?
dfs!
贴代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
#define mode 772002
using namespace std;
bool used[10][10];
bool maps[10][10];
int n,m;
ll dp[30][(1<<15)+5];
char ch[10];
int dir[10][2]={{0,0},{1,1},{1,0},{1,-1},{0,1},{0,-1},{-1,1},{-1,0},{-1,-1}};
int temp[30][2];
int num[(1<<15)+5];
ll ans=0;
bool check(int x,int y)
{
if(x>0&&x<=n&&y>0&&y<=m)
{
return 1;
}
return 0;
}
ll get_dp()
{
int cnt=0;
memset(dp,0,sizeof(dp));
memset(used,0,sizeof(used));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(maps[i][j])
{
used[i][j]=1;
temp[++cnt][0]=i;
temp[cnt][1]=j;
}
}
}
for(int i=0;i<=(1<<cnt)-1;i++)
{
int tot=0;
memset(used,0,sizeof(used));
for(int j=1;j<=cnt;j++)
{
if(!((1<<(j-1))&i))
{
if(!used[temp[j][0]][temp[j][1]])
{
used[temp[j][0]][temp[j][1]]=1;
tot++;
}
for(int t=1;t<=8;t++)
{
int x=temp[j][0]+dir[t][0];
int y=temp[j][1]+dir[t][1];
if(check(x,y)&&!used[x][y])
{
used[x][y]=1;
tot++;
}
}
}
}
num[i]=n*m-tot;
}
dp[0][0]=1;
for(int i=1;i<=n*m;i++)
{
for(int j=0;j<=(1<<cnt)-1;j++)
{
dp[i][j]+=dp[i-1][j]*max(num[j]-i+1,0)%mode;
dp[i][j]%=mode;
for(int k=1;k<=cnt;k++)
{
if(!((1<<(k-1))&j))
{
dp[i][j|(1<<(k-1))]+=dp[i-1][j];
dp[i][j|(1<<(k-1))]%=mode;
}
}
}
}
return dp[n*m][(1<<cnt)-1];
}
void dfs(int x,int y,int typ)
{
if(x==n+1)
{
if(typ%2)
{
ans-=get_dp();
ans%=mode;
}else
{
ans+=get_dp();
ans%=mode;
}
return;
}
if(y==m+1)
{
dfs(x+1,1,typ);
return;
}
dfs(x,y+1,typ);
if(!maps[x][y])
{
bool flag=0;
for(int i=1;i<=8;i++)
{
int st=x+dir[i][0];
int ed=y+dir[i][1];
if(maps[st][ed])
{
flag=1;
break;
}
}
if(!flag)
{
maps[x][y]=1;
dfs(x,y+1,typ+1);
maps[x][y]=0;
return;
}
}
}
int main()
{
int cot=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
cot++;
bool u=0;
memset(maps,0,sizeof(maps));
for(int i=1;i<=n;i++)
{
scanf("%s",ch);
for(int j=0;j<m;j++)
{
if(ch[j]=='.')
{
maps[i][j+1]=0;
}else
{
maps[i][j+1]=1;
if(maps[i-1][j+1]||maps[i][j])
{
u=1;
}
}
}
}
if(u)
{
printf("Case #%d: 0\n",cot);
continue;
}
ans=0;
dfs(1,1,0);
printf("Case #%d: %lld\n",cot,(ans%mode+mode)%mode);
}
return 0;
}
bzoj 2669 题解(状压dp+搜索+容斥原理)的更多相关文章
- BZOJ 2064: 分裂( 状压dp )
n1+n2次一定可以满足..然后假如之前土地集合S1的子集subs1和之后土地集合S2的子集subs2相等的话...那么就少了2个+操作...所以最后答案就是n1+n2-少掉的最多操作数, 由状压dp ...
- O - Matching 题解(状压dp)
题目链接 题目大意 给你一个方形矩阵mp,边长为n(n<=21) 有n个男生和女生,如果\(mp[i][j]=1\) 代表第i个男生可以和第j个女生配对 问有多少种两两配对的方式,使得所有男生和 ...
- [BZOJ 1879][SDOI 2009]Bill的挑战 题解(状压DP)
[BZOJ 1879][SDOI 2009]Bill的挑战 Description Solution 1.考虑状压的方式. 方案1:如果我们把每一个字符串压起来,用一个布尔数组表示与每一个字母的匹配关 ...
- 【Gym100837F】Controlled Tournament(状压Dp 搜索剪枝)
题目链接 大意 现有\(N\)个人要打比赛,知道任意两个人间打比赛的胜负关系. 要求在 深度最小 的情况下,根为\(M\)的 竞赛树 的个数. 满足\(1\le M\le N\le 16\) 思路 虑 ...
- 【BZOJ2560】串珠子(状压DP,容斥原理)
题意: 铭铭有n个十分漂亮的珠子和若干根颜色不同的绳子.现在铭铭想用绳子把所有的珠子连接成一个整体.现在已知所有珠子互不相同,用整数1到n编号.对于第i个珠子和第j个珠子,可以选择不用绳子连接,或者在 ...
- BZOJ 3812 主旋律 (状压DP+容斥) + NOIP模拟赛 巨神兵(obelisk)(状压DP)
这道题跟另一道题很像,先看看那道题吧 巨神兵(obelisk) 题面 欧贝利斯克的巨神兵很喜欢有向图,有一天他找到了一张nnn个点mmm条边的有向图.欧贝利斯克认为一个没有环的有向图是优美的,请问这张 ...
- 【uoj#37/bzoj3812】[清华集训2014]主旋律 状压dp+容斥原理
题目描述 求一张有向图的强连通生成子图的数目对 $10^9+7$ 取模的结果. 题解 状压dp+容斥原理 设 $f[i]$ 表示点集 $i$ 强连通生成子图的数目,容易想到使用总方案数 $2^{sum ...
- 【bzoj2560】串珠子 状压dp+容斥原理
题目描述 有 $n$ 个点,点 $i$ 和点 $j$ 之间可以连 $0\sim c_{i,j}$ 条无向边.求连成一张无向连通图的方案数模 $10^9+7$ .两个方案不同,当且仅当:存在点对 $(i ...
- NOIP2017 宝藏 题解报告【状压dp】
题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的 m 条道路和它们的长度. 小明决心亲自前往挖掘所有宝藏屋中的宝藏.但是 ...
随机推荐
- mysql 案例 ~ mysql字符集详解
一 谈谈mysql常见的字符集问题 二 字符集统一 1 character_set_server 2 character_set_client 3 java/php等连接字符集 4 chara ...
- 项目:《JavaWeb图书管理系统视频》--代码修复还可以运行起来
1. 系统设计--项目效果图请看最后面 1技术选型 (系统架构) JSTL + JSP + Servlet + JavaBean + BeanUtils + FileUpload + JavaMail ...
- Java学习过程中要记录的地方--汇总
1.Map的子类 HashMap 是哈希表,根据哈希算法来存的,取出来不一定是按照原来的循序: Ctrl+T 可以看到 HashMap下面有 LinkHashMap 是线性实现的,里面有顺序. --- ...
- 【转载】论文笔记系列-Tree-CNN: A Deep Convolutional Neural Network for Lifelong Learning
一. 引出主题¶ 深度学习领域一直存在一个比较严重的问题——“灾难性遗忘”,即一旦使用新的数据集去训练已有的模型,该模型将会失去对原数据集识别的能力.为解决这一问题,本文提出了树卷积神经网络,通过先将 ...
- PL/SQL 加字段 修改数据库之后 之后记得保存脚本
- 20165231 2017-2018-2 《Java程序设计》第7周学习总结
教材学习内容总结 第十一章 MySQL数据库管理系统,简称MySQL,是世界上最流行的开源数据库管理系统,其社区版(MySQL Community Edition)是最流行的免费下载的开源数据库管理系 ...
- 【Ubuntu】如何修改IP
前几天有幸捣鼓了一下Ubuntu系统,和Linux系统差不多,在这里说说如何修改IP 1,首先使用命令ifconfig查看当前IP,如图 2,编辑文件,输入命令 ...
- 数字图像处理的Matlab实现(4)—灰度变换与空间滤波
第3章 灰度变换与空间滤波(2) 3.3 直方图处理与函数绘图 基于从图像亮度直方图中提取的信息的亮度变换函数,在诸如增强.压缩.分割.描述等方面的图像处理中扮演着基础性的角色.本节的重点在于获取.绘 ...
- Trickbot增加的远程应用程序凭证抓取功能
来源 https://blog.trendmicro.com/trendlabs-security-intelligence/trickbot-adds-remote-application-cred ...
- python3 xml模块
一.简介 xml是实现不通语言或程序之间进行数据交换的协议,可扩展标记语言,标准通用标记语言的子集.是一种用于标记电子文件使其具有结构性的标记语言.xml格式如下,是通过<>节点来区别数据 ...