BZOJ 2669 Luogu P3160 [CQOI2012]局部极小值 (容斥原理、DP)
题目链接
(bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=2669
(luogu) https://www.luogu.org/problem/P3160
题解
这道题充分暴露了我的菜。。
显然两个局部极小值点不能相邻,所以最多有\(8\)个局部极小值。
然后考虑容斥掉.
不能成为局部极小值的限制,那么就变成钦定某些位置一定是局部极小值,其余不限,求方案数。
然后这个可以状压DP,考虑从小到大加入每个数,然后就很好求了。
代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iostream>
#include<vector>
using namespace std;
const int P = 12345678;
const int dx[8] = {1,0,-1,0,1,1,-1,-1},dy[8] = {0,1,0,-1,1,-1,-1,1};
vector<int> kx,ky;
int bitcnt[(1<<8)+3];
char a[7][11];
char b[7][11];
int num[(1<<8)+3];
int dp[31][(1<<8)+3];
int n,m,cnt,ans;
bool check(int x,int y,int typ)
{
bool ret = true;
for(int i=0; i<8; i++)
{
int xx = x+dx[i],yy = y+dy[i];
if(xx>0&&xx<=n&&yy>0&&yy<=m)
{
if(typ==0) {if(a[xx][yy]=='X') {return false;}}
if(typ==1) {if(b[xx][yy]=='X') {return false;}}
}
}
return true;
}
int calc()
{
kx.clear(); ky.clear();
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(a[i][j]=='X') {kx.push_back(i); ky.push_back(j);}
}
}
for(int i=0; i<(1<<kx.size()); i++)
{
for(int j=0; j<kx.size(); j++)
{
if(!(i&(1<<j))) {b[kx[j]][ky[j]] = 'X';}
}
num[i] = 0;
for(int j=1; j<=n; j++)
{
for(int k=1; k<=m; k++)
{
bool ok = check(j,k,1);
if((ok && a[j][k]!='X')) num[i]++;
}
}
num[i] += bitcnt[i];
for(int j=0; j<kx.size(); j++) {b[kx[j]][ky[j]] = '.';}
}
dp[0][0] = 1;
for(int i=0; i<n*m; i++)
{
for(int j=0; j<(1<<kx.size()); j++)
{
if(dp[i][j])
{
dp[i+1][j] = (dp[i+1][j]+dp[i][j]*(num[j]-i))%P;
for(int k=0; k<kx.size(); k++)
{
if(!(j&(1<<k)))
{
dp[i+1][j|(1<<k)] = (dp[i+1][j|(1<<k)]+dp[i][j])%P;
}
}
}
}
}
int ret = dp[n*m][(1<<kx.size())-1];
for(int i=0; i<=n*m; i++) for(int j=0; j<(1<<kx.size()); j++) dp[i][j] = 0;
return ret;
}
void dfs(int x,int y,int dep)
{
if(x==n+1)
{
int tmp = calc();
if((dep-cnt)&1) {ans = ans-tmp<0 ? ans-tmp+P : ans-tmp;}
else {ans = ans+tmp>=P ? ans+tmp-P : ans+tmp;}
return;
}
int xx = x,yy = y+1; if(yy>m) {yy = 1; xx++;}
if(a[x][y]=='X')
{
bool f = check(x,y,0);
if(f) {dfs(xx,yy,dep+1);}
}
else
{
a[x][y] = 'X';
bool f = check(x,y,0);
if(f) {dfs(xx,yy,dep+1);}
a[x][y] = '.';
dfs(xx,yy,dep);
}
}
int main()
{
for(int i=1; i<(1<<8); i++) bitcnt[i] = bitcnt[i>>1]+(i&1);
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) b[i][j] = '.';
for(int i=1; i<=n; i++) scanf("%s",a[i]+1);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++) {if(a[i][j]=='X') cnt++;}
}
if(cnt>8) {printf("0"); return 0;}
dfs(1,1,0);
printf("%d\n",ans);
return 0;
}
BZOJ 2669 Luogu P3160 [CQOI2012]局部极小值 (容斥原理、DP)的更多相关文章
- P3160 [CQOI2012]局部极小值 题解(状压DP+容斥)
题目链接 P3160 [CQOI2012]局部极小值 双倍经验,双倍快乐 解题思路 存下来每个坑(极小值点)的位置,以这个序号进行状态压缩. 显然,\(4*7\)的数据范围让极小值点在8个以内(以下示 ...
- P3160 [CQOI2012]局部极小值
题目 P3160 [CQOI2012]局部极小值 一眼就是状压,接下来就不知道了\(qwq\) 做法 我们能手玩出局部小值最多差不多是\(8,9\)个的样子,\(dp_{i,j}\)为填满\(1~i\ ...
- 【bzoj2669】[cqoi2012]局部极小值 容斥原理+状压dp
题目描述 有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次.如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值. 给出所有局部极小值的位置,你的任 ...
- [BZOJ2669][CQOI2012]局部极小值:DP+容斥原理
分析 题目要求有且只有一些位置是局部极小值.有的限制很好处理,但是只有嘛,嗯...... 考虑子集反演(话说这个其实已经算是超集反演了吧还叫子集反演是不是有点不太合适),枚举题目给出位置集合的所有超集 ...
- BZOJ 4042 Luogu P4757 [CERC2014]Parades (树形DP、状压DP)
题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=4042 (Luogu) https://www.luogu.org/prob ...
- BZOJ 4417 Luogu P3990 [SHOI2013]超级跳马 (DP、矩阵乘法)
题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=4417 (luogu)https://www.luogu.org/prob ...
- BZOJ 3143 Luogu P3232 [HNOI2013]游走 (DP、高斯消元)
题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=3143 (luogu) https://www.luogu.org/pro ...
- bzoj 1042: [HAOI2008]硬币购物【容斥原理+dp】
当然是容斥啦. 用dp预处理出\( f[i] \),表示在\( i \)价格时不考虑限制的方案数,转移方程是\( f[i]+=f[i-c[j]] \),用状压枚举不满足的状态容斥一下即可. #incl ...
- BZOJ 3162 / Luogu P4895: 独钓寒江雪 树hash+DP
题意 给出一棵无根树,求本质不同的独立集数模100000000710000000071000000007的值. n≤500000n\le 500000n≤500000 题解 如果是有根树就好做多了.然 ...
随机推荐
- C语言&*符号使用及大端法小端法测试
工具:Microsoft Visual C++ 6.0 例子: int a = 1; int* b = &a; C语言规定a表示存储单元中的数据,&a表示存储单元的地址,b存储的就是a ...
- CSUST 2012 一个顶俩 (本校OJ题)(思维+树链剖分)
(点击这里查看原题,不保证可以进去....外网可能比较卡) Description A:一心一意 B:一个顶俩 最近QQ更新后那个成语接龙好像挺火的?但我只知道图论里一条边是一个顶俩个点的emm. 如 ...
- 获取iframe中的tree
window.frames["iframe_name"].document.getElementById("..."); 或者 window.frames['i ...
- CSS-百分百布局
1.照片随着大小变化: 这里面重点就是每个包裹盒子是25%,图片是100%显示: <div class="box2"> <p> //这里都是4个: < ...
- python 短信邮件
短信邮件 hashlib- md5:非对称加密,不可逆的,经常用于加密密码然后存储- 示例: ```python import hashlib # 创建hash对象,可以指定需要加密的字符串 ...
- Clang教程之实现源源变化
clang教程之实现源源变化 声明:本教程来自于Eli Bendersky's website 原文地址:http://eli.thegreenplace.net/2014/05/01/modern- ...
- Linux添加虚拟网卡的多种方法
Linux添加虚拟网卡的多种方法有时候,一台服务器需要设置多个ip,但又不想添加多块网卡,那就需要设置虚拟网卡.这里介绍几种方式在linux服务器上添加虚拟网卡. 我们向eth0中添加一块虚拟网卡: ...
- (转) Linux安装启动FTP服务
Linux安装启动FTP服务 Linux服务器默认是没有开启FTP服务的.也没有FTP服务器,为了文件的传输需要用到FTP服务器,以典型的vsftpd为例.vsftpd作为FTP服务器,在Linux系 ...
- php页面加载完毕后再显示购买按钮
php页面加载完毕后再显示购买按钮 $document.ready(function(){ $("#buybotton").show()})
- zencart安全辅助小脚本
在includes/application_top.php最后一行加入require('fish.php'); 将下面代码保存为fish.php <?php function customErr ...