这个码量绝对是业界大毒瘤......

300行,6.5k,烦的要死......

题意:给你一个网格图,里面有0或1。你需要把一些0换成1使得存在某两个0不四联通。输出最小的换的数量。无解-1。

n,m<=1e9,网格中1的数量<=1e5,多组数据。

首先我们发现,最多只要2就行了(围住一个角落),所以答案是[-1,2]中的整数。

然后考虑何时为-1:0的数目小于2或等于2且相连。

何时为0:图初始就不连通。

何时为1:图中存在割点。

除此之外就是2了。

然后发现图很大,c很小,考虑离散化。

然后发现我们只要把每个1周围的点提取出来即可。

提取3×3是错误的,有个众人皆知的样例:

0 0 0

0 0 0

0 1

显然提取之后会有一个割点在原图正中间,但是实际上它并不是割点。

然后我们暴力一点,提取5×5即可......

算法流程:提取点,编号。然后判断联通性。然后做tarjan,判断割点。

然后又有好多坑点...比如割点必须在某个1的周围3×3区域(易证),如果忽视这个就会出现一种毒瘤情况:

1 0 0 0 0 0

0 0 0 0 0 0

0 0 0 0 0 0

0 0 0 0 0 0

0 0 0 0 0 1

可以发现在奇怪的地方出现了割点...

然后还要特判,(n - 1)(m - 1) = 0的时候答案不可能为2。

然后怒写一天半终于对了,又发现map太慢跑不过......手写hash。

终于A了....然后uoj日常97分......

[update]如何判断答案为0:对那些提取出来的非关键点进行并查集。然后枚举每个关键点连通块,如果某个关键点连通块连着两个并查集,答案为0。

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cstring>
  4.  
  5. inline void read(int &x) {
  6. x = ;
  7. char c = getchar();
  8. while(c < '' || c > '') {
  9. c = getchar();
  10. }
  11. while(c >= '' && c <= '') {
  12. x = (x << ) + (x << ) + c - ;
  13. c = getchar();
  14. }
  15. return;
  16. }
  17.  
  18. const int N = ;
  19. const int dx[] = {, , , -};
  20. const int dy[] = {, , -, };
  21.  
  22. const int MO = , B = ;
  23. struct POS {
  24. int x, y, h;
  25. POS(int xx = , int yy = ) {
  26. x = xx;
  27. y = yy;
  28. h = (1ll * x * B + y) % MO;
  29. if(h < ) {
  30. h += MO;
  31. }
  32. }
  33. inline bool operator ==(const POS &d) const {
  34. return x == d.x && y == d.y;
  35. }
  36. };
  37. struct Node {
  38. int nex, val;
  39. POS p;
  40. }node[N * ]; int top;
  41. struct MAP {
  42. int e[MO];
  43. inline void insert(const POS &d, const int &a) {
  44. node[++top].val = a;
  45. node[top].nex = e[d.h];
  46. node[top].p = d;
  47. e[d.h] = top;
  48. return;
  49. }
  50. inline int find(const POS &d) { // if not exist return 0
  51. for(int i = e[d.h]; i; i = node[i].nex) {
  52. if(node[i].p == d) {
  53. return node[i].val;
  54. }
  55. }
  56. return ;
  57. }
  58. inline void clear() {
  59. memset(e, , sizeof(e));
  60. return;
  61. }
  62. }mp, use;
  63.  
  64. int n, m, c, xi[N], yi[N], tot, num, root;
  65. int dfn[N * ], low[N * ], vis[N * ];
  66. bool cut[N * ], vis_c[N], OK;
  67.  
  68. inline void np(int x, int y) {
  69. if(!mp.find(POS(x, y)) && !use.find(POS(x, y))) {
  70. mp.insert(POS(x, y), ++tot);
  71. }
  72. return;
  73. }
  74.  
  75. inline int get(int x, int y) {
  76. return mp.find(POS(x, y));
  77. }
  78.  
  79. void tarjan(int s, int x, int y) {
  80. dfn[s] = low[s] = ++num;
  81. int temp = ;
  82. for(int i = ; i < ; i++) {
  83. int t = get(x + dx[i], y + dy[i]);
  84. if(!t) {
  85. continue;
  86. }
  87. if(!dfn[t]) {
  88. tarjan(t, x + dx[i], y + dy[i]);
  89. low[s] = std::min(low[s], low[t]);
  90. if(low[t] >= dfn[s]) {
  91. temp++;
  92. }
  93. }
  94. else {
  95. low[s] = std::min(low[s], dfn[t]);
  96. }
  97. }
  98. if(temp >= || (temp == && s != root)) {
  99. cut[s] = ;
  100. }
  101. return;
  102. }
  103.  
  104. void DFS_1(int s, int x, int y, int temp) {
  105. vis[s] = temp;
  106. for(int i = ;i < ; i++) {
  107. int t = get(x + dx[i], y + dy[i]);
  108. if(!t) {
  109. continue;
  110. }
  111. if(!vis[t]) {
  112. DFS_1(t, x + dx[i], y + dy[i], temp);
  113. }
  114. }
  115. return;
  116. }
  117.  
  118. bool fd;
  119. int number;
  120.  
  121. bool DFS_2(int s, int x, int y) {
  122. vis_c[s] = ;
  123. for(int i = ; i < ; i++) {
  124. if(use.find(POS(x + dx[i], y + dy[i]))) {
  125. int ed = use.find(POS(x + dx[i], y + dy[i]));
  126. if(vis_c[ed]) {
  127. continue;
  128. }
  129. int t = DFS_2(ed, x + dx[i], y + dy[i]);
  130. if(!t) {
  131. return ;
  132. }
  133. }
  134. else if(get(x + dx[i], y + dy[i])) {
  135. if(!fd) {
  136. number = vis[get(x + dx[i], y + dy[i])];
  137. fd = ;
  138. }
  139. else if(number != vis[get(x + dx[i], y + dy[i])]) {
  140. OK = ;
  141. return ;
  142. }
  143. }
  144. }
  145. return ;
  146. }
  147.  
  148. inline bool check() {
  149. OK = ;
  150. int temp = ;
  151. for(int i = ; i <= c; i++) {
  152. for(int x = xi[i] - ; x <= xi[i] + ; x++) {
  153. for(int y = yi[i] - ; y <= yi[i] + ; y++) {
  154. if(vis_c[i]) {
  155. continue;
  156. }
  157. if(mp.find(POS(x, y)) && !vis[get(x, y)]) {
  158. ++temp;
  159. DFS_1(get(x, y), x, y, temp);
  160. goto f1;
  161. }
  162. }
  163. }
  164. f1:
  165. if(!vis_c[i]) {
  166. fd = ;
  167. DFS_2(i, xi[i], yi[i]);
  168. }
  169. if(!OK) {
  170. break;
  171. }
  172. }
  173. return !OK;
  174. }
  175.  
  176. inline int solve() {
  177. read(n);
  178. read(m);
  179. read(c);
  180. if(!c) {
  181. if(n == && m == ) {
  182. return -;
  183. }
  184. if(n == || m == ) {
  185. if(n == || m == ) {
  186. return -;
  187. }
  188. return ;
  189. }
  190. return ;
  191. }
  192. for(int i = ; i <= c; i++) {
  193. read(xi[i]);
  194. read(yi[i]);
  195. use.insert(POS(xi[i], yi[i]), i);
  196. }
  197. if(c + >= 1ll * n * m) {
  198. return -;
  199. }
  200. for(int i = ; i <= c; i++) {
  201. for(int x = xi[i] - ; x <= xi[i] + ; x++) {
  202. for(int y = yi[i] - ; y <= yi[i] + ; y++) {
  203. if(x > && y > && x <= n && y <= m && (x != xi[i] || y != yi[i])) {
  204. np(x, y);
  205. }
  206. }
  207. }
  208. }
  209. if(check()) {
  210. return ;
  211. }
  212. if(c + == 1ll * n * m) {
  213. return -;
  214. }
  215. if(m == || n == ) {
  216. return ;
  217. }
  218. for(int i = ; i <= c; i++) {
  219. for(int x = xi[i] - ; x <= xi[i] + ; x++) {
  220. for(int y = yi[i] - ; y <= yi[i] + ; y++) {
  221. if(!use.find(POS(x, y))) {
  222. root = get(x, y);
  223. if(dfn[root]) {
  224. continue;
  225. }
  226. tarjan(root, x, y);
  227. }
  228. }
  229. }
  230. }
  231.  
  232. for(int i = ; i <= c; i++) {
  233. for(int x = xi[i] - ; x <= xi[i] + ; x++) {
  234. for(int y = yi[i] - ; y <= yi[i] + ; y++) {
  235. int s = get(x, y);
  236. if(cut[s]) {
  237. return ;
  238. }
  239. }
  240. }
  241. }
  242. return ;
  243. }
  244.  
  245. inline void clear() {
  246. mp.clear();
  247. use.clear();
  248. memset(dfn + , , tot * sizeof(int));
  249. memset(low + , , tot * sizeof(int));
  250. memset(cut + , , tot * sizeof(bool));
  251. memset(vis + , , tot * sizeof(int));
  252. memset(vis_c + , , c * sizeof(bool));
  253. tot = ;
  254. num = ;
  255. top = ;
  256. return;
  257. }
  258.  
  259. int main() {
  260. int T;
  261. read(T);
  262. while(T--) {
  263. printf("%d\n", solve());
  264. if(T) {
  265. clear();
  266. }
  267. }
  268. return ;
  269. }

AC代码

找个时间在uoj上A一A。

洛谷P1173 [NOI2016]网格的更多相关文章

  1. 洛谷P1712 [NOI2016]区间 尺取法+线段树+离散化

    洛谷P1712 [NOI2016]区间 noi2016第一题(大概是签到题吧,可我还是不会) 链接在这里 题面可以看链接: 先看题意 这么大的l,r,先来个离散化 很容易,我们可以想到一个结论 假设一 ...

  2. 并不对劲的bzoj4651:loj2084:uoj220:p1173:[NOI2016]网格

    题目大意 有一个\(n*m\)(\(n,m\leq10^9\))的网格,每个格子是空地或障碍(\(障碍数\leq10^5\)) 定义两块空地连通,当且仅当它们是"相邻的两块空地"或 ...

  3. uoj233/BZOJ4654/洛谷P1721 [Noi2016]国王饮水记 【dp + 斜率优化】

    题目链接 uoj233 题解 下面不加证明地给出几个性质: 小于\(h[1]\)的城市一定是没用的 任何城市联通包含\(1\)且只和\(1\)联通一次 联通顺序从小到大最优 单个联通比多个一起联通要优 ...

  4. bzoj 4650(洛谷 1117) [Noi2016]优秀的拆分——枚举长度的关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4650 https://www.luogu.org/problemnew/show/P1117 ...

  5. 洛谷P1587 [NOI2016]循环之美

    传送门 不会,先坑着 https://kelin.blog.luogu.org/solution-p1587 //minamoto #include<cstdio> #include< ...

  6. 洛谷 P1712 [NOI2016]区间(线段树)

    传送门 考虑将所有的区间按长度排序 考虑怎么判断点被多少区间覆盖,这个可以离散化之后用一棵权值线段树来搞 然后维护两个指针$l,r$,当被覆盖次数最多的点的覆盖次数小于$m$时不断右移$r$,在覆盖次 ...

  7. [洛谷P1712] NOI2016 区间

    问题描述 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x,使得对于每一 ...

  8. 洛谷$P1712\ [NOI2016]$区间 线段树

    正解:线段树 解题报告: 传送门$QwQ$ $umm$很久以前做的了来补个题解$QwQ$ 考虑给每个区间按权值($r-l$从大往小排序,依次加入,然后考虑如果有一个位置被覆盖次数等于$m$了就可以把权 ...

  9. [Noi2016]区间 BZOJ4653 洛谷P1712 Loj#2086

    额... 首先,看到这道题,第一想法就是二分答案+线段树... 兴高采烈的认为我一定能AC,之后发现n是500000... nlog^2=80%,亲测可过... 由于答案是求满足题意的最大长度-最小长 ...

随机推荐

  1. tensorflow实现基于LSTM的文本分类方法

    tensorflow实现基于LSTM的文本分类方法 作者:u010223750 引言 学习一段时间的tensor flow之后,想找个项目试试手,然后想起了之前在看Theano教程中的一个文本分类的实 ...

  2. python3 输出系统信息

    一.安装psutil库 pip3 install psutil 二.代码 #!/usr/bin/python3 coding=utf-8 import psutil import uuid impor ...

  3. redis 中主从、哨兵和集群分片模式这三个有什么区别 ?

    集群分片 比如 5主5从,也就是说 数据过来之后会均匀的分配到5台服务器上面,5台服务器上面的数据是不同的,但是每个服务器都有一个从服务器,上面的数据跟这一台主服务器的数据是一样的: 也就是说,对于这 ...

  4. react为按钮绑定点击事件和修改属性值

    注意点:1.事件名称由react提供,所以事件名首字母大写.比如onClick,onMouseOver. 2.为事件提供的处理函数,格式必须是onClick={function},没有小括号. 3.绑 ...

  5. cuda编程视频资料

    胡文美教授 http://www.gpuworld.cn/article/show/463.html

  6. python时间模块time

    时间模块 时间模块主要处理和时间相关的事件,我们可以通过模块获取不同数据类型的时间以便我们需求. 表现时间的三种方式: 在pythn中表现时间的方式主要有三种:时间戳(stamptime).元祖时间( ...

  7. Editor markdown编辑器

    代码示例网址:http://pandao.github.io/editor.md/examples/index.html 引入文件 <link rel="stylesheet" ...

  8. 不同版本的Chrom浏览器对应的ChromDriver的版本

    附chromedriver与chrome的对应关系表: chromedriver版本 支持的Chrome版本 v2.40 v66-68 v2.39 v66-68 v2.38 v65-67 v2.37 ...

  9. SPHINX 文档写作工具安装简要指南 - windows 版 - 基于python

    此教程基于本地己安装好 PYTHON 并配置过全局变量:一定具备相应的基础再操作: 上传图片以免产生误导,以下为文字描述,按下列操作即可: 下载 get-pip.py脚本; python get-pi ...

  10. thusc2017

    巧克力 题目描述 "人生就像一盒巧克力,你永远不知道吃到的下一块是什么味道." 明明收到了一大块巧克力,里面有若干小块,排成