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 条道路和它们的长度. 小明决心亲自前往挖掘所有宝藏屋中的宝藏.但是 ...
随机推荐
- cxf动态调用外部web service 报告异常java.lang.NoSuchFieldError: QUALIFIED
原因:cxf 依赖的xmlschema-core 与xfire-all依赖的xmlschema冲突.(百度搜索亦得知:cxf 依赖的xmlschema-core 与axis2-kernel依赖的xml ...
- linux上安装Docker(非常简单的安装方法)
Docker的三大核心概念:镜像.容器.仓库 镜像:类似虚拟机的镜像.用俗话说就是安装文件. 容器:类似一个轻量级的沙箱,容器是从镜像创建应用运行实例, 可以将其启动.开始.停止.删除.而这些容器都是 ...
- Nginx在局域网中使用ip_hash负载均衡策略,访问全部分发到同一个后台服务器
Nginx的ip_hash算法都将一个ip地址的前三段作为hash的关键字
- Spring Boot:如何配置静态资源的地址与访问路径
spring.resources.static-locations=classpath:/static,classpath:/public,classpath:/resources,classpath ...
- SQL Server - 哈希索引
转载自:https://blog.csdn.net/josjiang1/article/details/80637076 作者:josjiang1 ————————总结———————— 使用场景: 1 ...
- Vue获取事件源
设置事件源 <label :data-weight="item1.EvaluateWeight" @click='radioClick' :data-id="ite ...
- python2x与python3x的区别
python2x与Python3x的区别 一.1.Python2x: a.源码不规范,源码混乱,重复代码冗余(重复多) python3x: b.重整源码,源码规范,优美,清新,简单 2.Python2 ...
- Maya API Test
import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx sl = OpenMaya.MSelectionList ...
- Win2008R2配置WebDeploy发布网站
一.配置服务器 1.安装管理服务 2.点击管理服务进行配置 二.安装WebDeploy 2.1通过离线安装包方式安装: https://www.iis.net/downloads/microsoft/ ...
- MySQL--表操作(innodb表字段数据类型、约束条件)、sql_mode操作
一.创建表的完整语法 #[]内的可有可无,即创建表时字段名和类型是必须填写的,宽度与约束条件是可选择填写的.create table 表名(字段名1 类型[(宽度) 约束条件],字段名2 类型[(宽度 ...