嘟嘟嘟

谁说CQOI的题都是板儿题,我就觉得这题挺难的……

看到数据范围这么小,就会想状压。然而\(2 ^ {28}\)肯定过不了。不过对于所有的极小值的格子,最多不会超过8个,所以我们状压选了哪些局部极小值的格子(坑儿)。

然后我们从小到大填数,那么对于一个数\(i\),他无非就两种填法:填入一个坑,或是填坑以外的点。
填一个坑儿就是直接填,于是有\(dp[i][S] = \sum dp[i - 1][S\) ^ \((1 << k)]\)。
不填坑的话,得考虑填上这个数之后,那些还没有填的坑仍能保证是坑,即不能往他们的四周填。因此我们预处理出来对于当前每一个状态,可以填的格子数目\(num[S]\)。然后有转移方程\(dp[i][S] = dp[i - 1][S] * (num[S] - (i - 1))\)。
答案就是\(dp[n * m][(1 << tot) - 1]\),\(tot\)是坑的总数。

但光这样是不对的。因为一些不是坑的点填完后可能成为了坑,换句话说,我们上面的\(dp[n * m][(1 << tot) -1]\)表示的是至少有\(tot\)个坑时的方案数,而我么需要的是恰好有这么多坑的方案数。
那么就能想到容斥了!我们暴力枚举棋盘上哪些格子可以是坑,然后每构造一个棋盘,就dp一次,然后看看是加上还是减去。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<assert.h>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const ll mod = 12345678;
In ll read()
{ll ans = 0;char ch = getchar(), last = ' ';while(!isdigit(ch)) last = ch, ch = getchar();while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();if(last == '-') ans = -ans;return ans;
}
In void write(ll x)
{if(x < 0) x = -x, putchar('-');if(x >= 10) write(x / 10);putchar(x % 10 + '0');
}
In void MYFILE()
{
#ifndef mrclrfreopen(".in", "r", stdin);freopen(".out", "w", stdout);
#endif
}int n, m, TOT;
char s[5][8];
ll ans = 0;In ll inc(ll a, ll b) {return a + b < mod ? a + b : a + b - mod;}struct Node
{int x, y;
}t[30];
int tot = 0, num[(1 << 8) + 5];
bool vis[5][8];
ll dp[30][(1 << 8) + 5];
const int dx[] = {-1, -1, 0, 1, 1, 1, 0, -1}, dy[] = {0, 1, 1, 1, 0, -1, -1, -1};
In void calc()
{tot = 0;for(int i = 1; i <= n; ++i)for(int j = 1; j <= m; ++j)if(s[i][j] == 'X') t[++tot] = (Node){i, j};for(int i = 0; i < (1 << tot); ++i){Mem(vis, 0);for(int j = 1; j <= tot; ++j)if(!((i >> (j - 1)) & 1)){vis[t[j].x][t[j].y] = 1;for(int k = 0; k < 8; ++k){int nx = t[j].x + dx[k], ny = t[j].y + dy[k];if(nx && nx <= n && ny && ny <= m) vis[nx][ny] = 1;}}int cnt = 0;for(int j = 1; j <= n; ++j)for(int k = 1; k <= m; ++k) cnt += vis[j][k];num[i] = n * m - cnt;}Mem(dp, 0); dp[0][0] = 1;for(int i = 1; i <= n * m; ++i){for(int S = 0; S < (1 << tot); ++S){dp[i][S] = inc(dp[i][S], dp[i - 1][S] * (num[S] - i + 1) % mod);for(int j = 0; j < tot; ++j)if((S >> j) & 1) dp[i][S] = inc(dp[i][S], dp[i - 1][S ^ (1 << j)]);}}ll tp = dp[n * m][(1 << tot) - 1];ans = inc(ans, ((tot - TOT) & 1) ? mod - tp: tp);
}In void dfs(int x, int y)
{if(x == n + 1) {calc(); return;}if(y == m) dfs(x + 1, 1);else dfs(x, y + 1);if(s[x][y] == 'X') return;bool flg = 1;for(int i = 0; i < 8 && flg; ++i){int nx = x + dx[i], ny = y + dy[i];if(nx && nx <= n && ny && ny <= m)if(s[nx][ny] == 'X') flg = 0;}if(!flg) return;s[x][y] = 'X';if(y == m) dfs(x + 1, 1);else dfs(x, y + 1);s[x][y] = '.';
}int main()
{//MYFILE();n = read(), m = read();for(int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);for(int i = 1; i <= n; ++i)for(int j = 1; j <= m; ++j) TOT += (s[i][j] == 'X');dfs(1, 1);write(ans), enter;return 0;
}

转载于:https://www.cnblogs.com/mrclr/p/10943389.html

[CQOI2012]局部极小值相关推荐

  1. P3160 [CQOI2012]局部极小值

    题目 P3160 [CQOI2012]局部极小值 一眼就是状压,接下来就不知道了\(qwq\) 做法 我们能手玩出局部小值最多差不多是\(8,9\)个的样子,\(dp_{i,j}\)为填满\(1~i\ ...

  2. BZOJ 2669 Luogu P3160 [CQOI2012]局部极小值 (容斥原理、DP)

    题目链接 (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=2669 (luogu) https://www.luogu.org/prob ...

  3. [CQOI2012] 局部极小值(状压DP + 容斥 + 搜索)

    problem luogu-P3160 solution 这么小的数据范围,非暴力不状压.暴力 O(28!)O(28!)O(28!) 呵呵呵可以拉走了. 我们不妨从小到大填数字,这样如果局部极小值点还 ...

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

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

  5. 【BZOJ-2669】局部极小值 状压DP + 容斥原理

    2669: [cqoi2012]局部极小值 Time Limit: 3 Sec  Memory Limit: 128 MB Submit: 561  Solved: 293 [Submit][Stat ...

  6. Java项目迁移到uap上_Tomcat启动,不能加载项目问题。

    [BZOJ-2669]局部极小值 状压DP + 容斥原理 2669: [cqoi2012]局部极小值 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 56 ...

  7. 灭霸消灭一般人口是随即的吗_是时候消灭皇家战斗风格了

    灭霸消灭一般人口是随即的吗 Fortnite was my first battle royale, as I'm sure it was for many. I thought at the tim ...

  8. 组合数学学习笔记(未完待续

    这学期学了不少组合数学,期末给他补完. 算法竞赛考得很多的部分啊 这个还是很重要的 在目前的算法竞赛中有三大计数考点 1)组合计数 2)线性计数 3)群论计数 其中群论计数比较困难,我又不知道什么是线 ...

  9. 2019.2-2019.3 TO-DO LIST

    DP P2723 丑数 Humble Numbers(完成时间:2019.3.1) P2725 邮票 Stamps(完成时间:2019.3.1) P1021 邮票面值设计(完成时间:2019.3.1) ...

最新文章

  1. Spring Cloud Data Flow 中的 ETL
  2. C++多线程简单入门(二)(Windows版)
  3. QJson生成文件和解析文件
  4. jQuery的选择器分类
  5. PhpStorm中绘画UML
  6. linux内核设计与实现看不懂,Linux内核设计与实现读书笔记
  7. iOS之深入解析CFRunloop的多线程隐患
  8. tensorflow包_在Keras和Tensorflow中使用深度卷积网络生成Meme(表情包)文本
  9. 牛客16464 神奇的幻方
  10. 基于MaxCompute分布式Python能力的大规模数据科学分析
  11. (转) OpenLayers3基础教程——加载资源
  12. 终极分类器(识别器),一个人工智能的美好愿景
  13. 你所不知道的 AI 进展
  14. 安大计算机学院ACM,全员考研上岸、ACM大赛获奖,乘风破浪的学霸寝室!
  15. 米家扫地机器人 设置不停止_【小米 米家 扫地机器人使用总结】设置|清扫_摘要频道_什么值得买...
  16. ucserver admin.php,Discuz!X3.2 升级后【ucenter、uc_server密码正确无法登录后台的解决方法】...
  17. 宁德时代与戴姆勒卡车股份公司扩大全球合作伙伴关系
  18. css+js 实现炫酷的魔方旋转
  19. 2020-10-29matlab中如何将字符串和数字一起输出到Excel中
  20. HTML/JSP/CSS网页编写实例,附源码

热门文章

  1. 关于机房精密空调监控系统,你想了解的都在这里!
  2. 芋道 Spring Cloud Alibaba 介绍
  3. error: converting to execution character set: Invalid or incomplete multibyte or wide character
  4. python微信图片dat转码(整理版)
  5. 最近做到一道好题,特来和大家分享一下。
  6. php 万能仿站--孙琪峥
  7. Elasticsearch[学习笔记]
  8. ABP Vnext 学习02-授权中心 重写Login 页面
  9. java web怎么实现踢人_【Java】浅谈踢人下线的设计思路!(附代码实现方案)
  10. 计算机网络谢希仁第七版答案