上课讲的一道题,感觉也挺厉害的~正解是容斥 + 状压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. SQL计算出百分比

    有clients和lead_sources俩表.mysql数据库. lead_sources表结构类似: clients表中的lead_source_id是外键.现在要统计某时间段内client内每种 ...

  2. leetcode笔记11 First Unique Character in a String

    题目描述: Given a string, find the first non-repeating character in it and return it's index. If it does ...

  3. 浅析JVM内存区域及垃圾回收

    一.JVM简介 JVM,全称Java Virtual Machine,即Java虚拟机.以Java作为编程语言所编写的应用程序都是运行在JVM上的.JVM是一种用于计算设备的规范,它是一个虚构出来的计 ...

  4. python编程os、os.path 模块中关于文件、目录常用的函数使用方法

    os模块中关于文件/目录常用的函数使用方法   函数名 使用方法 getcwd() 返回当前工作目录 chdir(path) 改变工作目录 listdir(path='.') 列举指定目录中的文件名( ...

  5. Codeforces Round #495 (Div. 2) Sonya and Matrix

    正常没有正方形的限制下,值为i的点个数4i 那么从0开始遍历,第一个不为4i的值就是min(x, y) 由于对称性我们姑且令x为这个值 我们先列举n*m=t的各种情况 对于一对n, m.我们已经知道n ...

  6. 关于axios跨域带cookie

    axios  设置 withCredentials :true $u = $_SERVER['HTTP_REFERER'];$u = preg_replace('#/$#', '', $u);head ...

  7. 【JSON类】使用说明

    理解键名路径 键名路径(keyPath)用于定位json的键,比如:{book: {title:”中国人”} },键名路径 book.title 表定位到book下的title键. 对于值是数组类型的 ...

  8. django 增删改查操作 数据库Mysql

    下面介绍一下django增删改查操作: 1.view.py # -*- coding: utf-8 -*-from __future__ import unicode_literalsfrom dja ...

  9. python程序设计——面向对象程序设计:类

    理解面向对象 基本原则是,计算机程序由多个能够起到子程序作用的单元或对象组合而成 关键性观念是,数据以及对数据的操作封装在一起,组成一个相互依存.不可分割的整体,即对象 python面向对象特性 完全 ...

  10. POJ 3046

    题目大意:蚂蚁牙黑,蚂蚁牙红:有A只蚂蚁,来自T个家族,分别记为ant[i]个.同一个家族的蚂蚁长得一样,但是不同家族的蚂蚁牙齿颜色不同.任取n只蚂蚁(S <= n <= B),求能组成几 ...