上课讲的一道题,感觉也挺厉害的~正解是容斥 + 状压dp。首先我们容易发现一共可能的局部最小值数量是十分有限的,最多也只有 \(8\) 个。所以我们可以考虑状压。

  建立出状态 \(f[i][j]\) 表示我们从小到大往方格当中填数,填完前\(i\) 个数之后,局部最小值的填充状态为 \(j\) 的方案数。这样一共有两种转移 :

\(f[i][j] = f[i - 1][j] * (g[j] - ((i - 1) - |j|)) + \sum f[i][j']\)

  分别表示加入了一个局部最小值 / 其他位置的值。其中的 \(g[j]\) 表示在 \(j\) 的状态下可以放入的非局部最小值的个数。但这样做出来还是不够的——我们虽然保证了要求的位置上一定是局部最小值,但是其余的位置上也有可能是局部最小值,而这是不符合要求的。我们考虑用容斥来处理,用全集 - 至少有一个非局部最小值成为了局部最小值的方案数,+至少两个,-至少三个……

  每一个dfs出来的状态都用上面的方法dp加入到答案中去就可以了。

#include <bits/stdc++.h>
using namespace std;
#define maxn 400
#define maxm 500
#define int long long
#define mod 12345678
int n, m, N, tot, cnt, ans;
int Map[maxn][maxn], id[maxn][maxn];
int f[maxn][maxm], g[maxm], T;
int dx[] = {-, , , -, , -, , };
int dy[] = {-, -, -, , , , , }; struct node
{
int x, y;
}P[maxn]; void Up(int& x, int y) { x = (x + y) % mod; } int DP()
{
int K = ( << tot) - ;
for(int k = ; k <= K; k ++)
{
g[k] = ; int tem = k, len = ;
while(tem) len += (tem & ), tem >>= ;
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
{
int flag = ; if(Map[i][j]) continue;
for(int l = ; l < ; l ++)
{
int x = i + dx[l], y = j + dy[l];
if(Map[x][y] && !(( << (id[x][y] - )) & k))
{ flag = ; break; }
}
if(!flag) g[k] ++;
}
g[k] += len;
}
memset(f, , sizeof(f)); f[][] = ;
for(int i = ; i <= N; i ++)
for(int j = ; j <= K; j ++)
{
Up(f[i][j], f[i - ][j] * (g[j] - (i - )));
int tem = j, len = ;
while(tem) len ++, tem >>= ;
for(int k = ; k < len; k ++)
if(j & ( << k)) Up(f[i][j], f[i - ][j ^ ( << k)]);
}
return f[N][K];
} void DFS(int x, int y)
{
if(y > m) x += , y = ;
if(x > n)
{
if((tot - cnt) & ) ans = (ans - DP() + mod) % mod;
else ans = (ans + DP()) % mod;
return;
}
DFS(x, y + );
if(Map[x][y]) return;
for(int i = ; i < ; i ++)
if(Map[x + dx[i]][y + dy[i]]) return;
Map[x][y] = , P[++ tot].x = x, P[tot].y = y; id[x][y] = tot;
DFS(x, y + );
tot --, Map[x][y] = , id[x][y] = ;
} signed main()
{
scanf("%lld%lld", &n, &m); N = n * m;
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
{
char c; cin >> c;
if(c == 'X')
{
P[++ tot].x = i, P[tot].y = j;
Map[i][j] = , id[i][j] = tot;
}
}
cnt = tot;
for(int i = ; i <= tot; i ++)
{
T |= ( << (i - ));
for(int j = ; j < ; j ++)
if(Map[P[i].x + dx[j]][P[i].y + dy[j]])
{
printf("");
return ;
}
}
DFS(, );
printf("%lld\n", ans);
return ;
}

【题解】CQOI2012局部最小值的更多相关文章

  1. [BZOJ2669][CQOI2012]局部最小值(容斥+状压DP)

    发现最多有8个限制位置,可以以此为基础DP和容斥. $f_{i,j}=f_{i-1,j}\times (cnt_j-i+1)+\sum_{k\subset j} f_{i-1,k}$ $cnt_j$表 ...

  2. 【noip模拟】局部最小值

    TimeLimit: 1000ms               MemoryLimit: 256MB Description 有一个n行m列的整数矩阵,其中1到n×m之间的每个整数恰好出现一次.如果一 ...

  3. 关于过拟合、局部最小值、以及Poor Generalization的思考

    Poor Generalization 这可能是实际中遇到的最多问题. 比如FC网络为什么效果比CNN差那么多啊,是不是陷入局部最小值啊?是不是过拟合啊?是不是欠拟合啊? 在操场跑步的时候,又从SVM ...

  4. [nowCoder] 局部最小值位置

    定义局部最小的概念.arr长度为1时,arr[0]是局部最小.arr的长度为N(N>1)时,如果arr[0]<arr[1],那么arr[0]是局部最小:如果arr[N-1]<arr[ ...

  5. ●BZOJ 2669 [cqoi2012]局部极小值

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2669 题解: 容斥,DP,DFS 先看看 dp 部分:首先呢,X的个数不会超过 8个.个数很 ...

  6. BZOJ2669 [cqoi2012]局部极小值 状压DP 容斥原理

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2669 题意概括 有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次.如果一个格子比所 ...

  7. 【bzoj2669】[cqoi2012]局部极小值 容斥原理+状压dp

    题目描述 有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次.如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值. 给出所有局部极小值的位置,你的任 ...

  8. bzoj2669 [cqoi2012]局部极小值 状压DP+容斥

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2669 题解 可以发现一个 \(4\times 7\) 的矩阵中,有局部最小值的点最多有 \(2 ...

  9. Mathematica 中 Minimize函数无法找到全局最小值时的解决方法

    一直使用Minimize来找到指定约束下的函数的最小值,最近发现在一个非线性函数中使用Minimize无法提供一个"全局"最小值(使用Mathematica只是用来验证算法的,所以 ...

随机推荐

  1. Python:pickle模块学习

    1. pickle模块的作用 将字典.列表.字符串等对象进行持久化,存储到磁盘上,方便以后使用 2. pickle对象串行化 pickle模块将任意一个python对象转换成一系统字节的这个操作过程叫 ...

  2. (转)Ruby On Rails 推荐 Gem 列表

    作者:尘缘,QQ:130775,来源:http://www.4wei.cn/archives/1002157 PHP的包管理Composer还在刚刚兴起的阶段,Ruby社区已经有很多成熟的Gem了,R ...

  3. ruby 技巧 根据函数的返回

    一般语言中,函数必须有返回值,即要带个return关键字.但在ruby中,return不是必须的,如果不写会默认返回最终计算的结果.举例 def add(a,b) # 省去了return a + b ...

  4. 【廖雪峰老师python教程】——IO编程

    同步IO 异步IO 最常见的IO——读写文件 读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一 ...

  5. 第3章 TCP协议详解

    第3章 TCP协议详解 3.1 TCP服务的特点 传输协议主要有两个:TCP协议和UDP协议,TCP协议相对于UDP协议的特点是 面向连接使用TCP协议通信的双方必须先建立连接,完成数据交换后,通信双 ...

  6. Python 作用域和命名空间

    在介绍类之前,我首先要告诉你一些Python的作用域规则.类定义对命名空间有一些巧妙的技巧,你需要知道作用域和命名空间如何工作才能完全理解正在发生的事情.顺便说一下,关于这个主题的知识对任何高级Pyt ...

  7. win 下通过dos命令格式化磁盘

    该命令可以解决好多问题,比如: 1.u盘作为启动后,如何恢复成正常的u盘 1.win + r ->cmd 进入dos模式 2.输入diskpart后回车,点击确定,进入diskpart命令的交互 ...

  8. CodeForces - 776C(前缀和+思维)

    链接:CodeForces - 776C 题意:给出数组 a[n] ,问有多少个区间和等于 k^x(x >= 0). 题解:求前缀和,标记每个和的个数.对每一个数都遍历到1e5,记录到答案. # ...

  9. Redis 数据结构服务器

    Redis 简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久 ...

  10. springMVC怎么改变form的提交方式为put或者delete

    想着练习一下创建restful风格的网站呢,结果发现在jsp页面上并不能灵活使用put和delete提交方式.下面我的解决办法 一. form 只支持post和get两种提交方式,只支持get提交方式 ...