Binary Table (Hard Version)

题意

\(n*m(2\le n,m\le 100)\) 的01矩阵,每次可以选择一个宽度为2的子矩阵,将四个位置中的任意3个进行翻转,即0变1,1变0。要求构造操作次数小于 \(n*m\) 的方案,使得该矩阵最终变成一个全0矩阵。

分析

构造方法可能有很多种,只要能够满足题意即可。

从第一行开始到倒数第三行,逐列扫描,假设当前扫描的位置为 (i,j),且当前位置为1,那么执行操作一或者操作二。\(i\le n-2\) ,只扫描前 \(n-2\) 行,最后空下两行特殊处理。这之前的 \((n-2)*m\) 个位置,总共使用了不超过 \((n-2)*m\) 次操作。

处理最后两行时,需要4个一组进行处理。分情况讨论

  1. 如果 4 个都是 ‘1’ ,进行一次翻转,只留右下角的 1,这个 1 留到最后处理

  1. 如果有某 3 个是 ‘1’ ,那么一次操作可以搞定

  1. 如果有某 2 个是 '1',那么可以细分为两种情况,这两种情况都可以用两步解决

  1. 如果只有 1 个是 '1',那么留作最后考虑。

根据上面的情况,对最后两行进行处理,如果 \(m\) 是偶数,刚好可以处理完。但如果 \(m\) 是奇数,那么对于最后一列的两个格子,我们需要特殊考虑。

可以想到,我们按照 4 个一组处理完左边四个之后,最多只会在 (n,m-1) 这个位置留一个 1,那么不论第 m 列是什么情况,我们都可以在两步操作内,将他们变为0。这个操作是绝对保险的。

最后,只剩下最后两行的某些单独的 1 了,这些单独的 1 可以在 3 步内消除,至于为什么这么操作不会使得操作次数爆炸,可以从这些 1 的产生来源考虑。

  1. 这个 1 原本就摆在这里,那么旁边 3 个空位之前是没有操作过的,这就给这个 1 留下了多余的操作空间。

  2. 这个 1 是消了 3 个之后剩下的,那么消除那 3 个用了一次,消除单独的 1 用了 3 次,刚好四次。

  3. 对于 m 为奇数时,最右边一列中单独的 1,这个虽然也需要使用 3 步,但是由于此时 m-1 列都是空的,这得多亏左边那四个之前是消除干净了的。而 4 个一组消除干净最多只需要两步,所以这种情况也是保险的。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 101;
  4. int T, n, m, t[N][N];
  5. char s[N][N];
  6. vector<pair<int,int> > v;
  7. void add(int x, int y){
  8. v.push_back({x, y});
  9. t[x][y] ^= 1;
  10. }
  11. void add(int x, int y, int p){
  12. if(p == 0) add(x, y);
  13. else if(p == 1) add(x, y+1);
  14. else if(p == 2) add(x+1, y);
  15. else if(p == 3) add(x+1, y+1);
  16. }
  17. void solve(int x, int y){
  18. int c0 = t[x][y];
  19. int c1 = t[x][y+1];
  20. int c2 = t[x+1][y];
  21. int c3 = t[x+1][y+1];
  22. int c = c0 + c1 + c2 + c3;
  23. if(c == 4) {
  24. add(x, y, 0);
  25. add(x, y, 1);
  26. add(x, y, 2);
  27. } else if(c == 3) {
  28. if(c0 == 0) add(x, y, 1), add(x, y, 2), add(x, y, 3);
  29. if(c1 == 0) add(x, y, 0), add(x, y, 2), add(x, y, 3);
  30. if(c2 == 0) add(x, y, 0), add(x, y, 1), add(x, y, 3);
  31. if(c3 == 0) add(x, y, 0), add(x, y, 1), add(x, y, 2);
  32. } else if(c == 2){
  33. if(c0 && c1) {
  34. add(x, y, 0);add(x, y, 2);add(x, y, 3);
  35. add(x, y, 1);add(x, y, 2);add(x, y, 3);
  36. } else if(c0 && c2) {
  37. add(x, y, 0);add(x, y, 1);add(x, y, 3);
  38. add(x, y, 2);add(x, y, 1);add(x, y, 3);
  39. } else if(c0 && c3) {
  40. add(x, y, 0);add(x, y, 1);add(x, y, 2);
  41. add(x, y, 3);add(x, y, 1);add(x, y, 2);
  42. } else if(c1 && c2){
  43. add(x, y, 1);add(x, y, 0);add(x, y, 3);
  44. add(x, y, 2);add(x, y, 0);add(x, y, 3);
  45. } else if(c1 && c3) {
  46. add(x, y, 1);add(x, y, 0);add(x, y, 2);
  47. add(x, y, 3);add(x, y, 0);add(x, y, 2);
  48. } else if(c2 && c3) {
  49. add(x, y, 2);add(x, y, 0);add(x, y, 1);
  50. add(x, y, 3);add(x, y, 0);add(x, y, 1);
  51. }
  52. }
  53. }
  54. int main(){
  55. scanf("%d", &T);
  56. while(T--){
  57. scanf("%d%d", &n, &m);
  58. for(int i=1;i<=n;i++) scanf("%s", s[i]+1);
  59. for(int i=1;i<=n;i++){
  60. for(int j=1;j<=m;j++){
  61. t[i][j] = s[i][j] - '0';
  62. }
  63. }
  64. for(int i=1;i<=n-2;i++){
  65. for(int j=1;j<=m;j++){
  66. if(t[i][j] == 0) continue;
  67. add(i, j); add(i+1, j);
  68. if(j == m) add(i+1, j-1);
  69. else add(i, j+1);
  70. }
  71. }
  72. for(int j = 1; j + 1 <= m; j += 2){
  73. solve(n - 1, j);
  74. }
  75. if(m & 1) solve(n - 1, m - 1);
  76. // 处理倒数第二行中单着的
  77. for(int j = 1; j <= m; j++){
  78. if(t[n-1][j] == 0) continue;
  79. if(j == m) {
  80. add(n-1, j-1, 1); add(n-1, j-1, 0); add(n-1, j-1, 3);
  81. add(n-1, j-1, 0); add(n-1, j-1, 2); add(n-1, j-1, 1);
  82. add(n-1, j-1, 3); add(n-1, j-1, 2); add(n-1, j-1, 1);
  83. } else {
  84. add(n-1, j, 0); add(n-1, j, 1); add(n-1, j, 2);
  85. add(n-1, j, 2); add(n-1, j, 0); add(n-1, j, 3);
  86. add(n-1, j, 1); add(n-1, j, 0); add(n-1, j, 3);
  87. }
  88. }
  89. // 处理倒数第一行单着的
  90. for(int j = 1; j <= m; j++){
  91. if(t[n][j] == 0) continue;
  92. if(j == m) {
  93. add(n-1, j-1, 3); add(n-1, j-1, 2); add(n-1, j-1, 1);
  94. add(n-1, j-1, 2); add(n-1, j-1, 0); add(n-1, j-1, 3);
  95. add(n-1, j-1, 1); add(n-1, j-1, 0); add(n-1, j-1, 3);
  96. } else {
  97. add(n-1, j, 2); add(n-1, j, 0); add(n-1, j, 3);
  98. add(n-1, j, 0); add(n-1, j, 1); add(n-1, j, 2);
  99. add(n-1, j, 3); add(n-1, j, 1); add(n-1, j, 2);
  100. }
  101. }
  102. cout << v.size() / 3 << endl;
  103. for(int i=0;i<v.size();){
  104. #define x first
  105. #define y second
  106. printf("%d %d %d %d %d %d\n", v[i].x, v[i].y, v[i+1].x, v[i+1].y, v[i+2].x, v[i+2].y);
  107. i += 3;
  108. }
  109. v.clear();
  110. }
  111. return 0;
  112. }

CF-1440C2 Binary Table (Hard Version) (构造,模拟)的更多相关文章

  1. CF 1003B Binary String Constructing 【构造/找规律/分类讨论】

    You are given three integers a, b and x. Your task is to construct a binary string s of length n=a+b ...

  2. CF 662C Binary Table

    用FWT优化计算. 首先发现行数很小,想到一个暴力的方法,就是以一个二进制位$0$表示这一行不翻转而二进制位$1$表示这一行翻转,然后$2^n$枚举出所有行的翻转情况,再$O(m)$计算所有的结果. ...

  3. D2. Kirk and a Binary String (hard version) D1 Kirk and a Binary String (easy version) Codeforces Round #581 (Div. 2) (实现,构造)

    D2. Kirk and a Binary String (hard version) time limit per test1 second memory limit per test256 meg ...

  4. 【CF662C】Binary Table(FWT)

    [CF662C]Binary Table(FWT) 题面 洛谷 CF 翻译: 有一个\(n*m\)的表格(\(n<=20,m<=10^5\)), 每个表格里面有一个\(0/1\), 每次可 ...

  5. [CF662C Binary Table][状压+FWT]

    CF662C Binary Table 一道 FWT 的板子-比较难想就是了 有一个 \(n\) 行 \(m\) 列的表格,每个元素都是 \(0/1\),每次操作可以选择一行或一列,把 \(0/1\) ...

  6. CROC 2016 - Final Round [Private, For Onsite Finalists Only] C. Binary Table FWT

    C. Binary Table 题目连接: http://codeforces.com/problemset/problem/662/C Description You are given a tab ...

  7. 【CF662C】Binary Table 按位处理

    [CF662C]Binary Table 题意:给你一个$n\times m$的01网格,你可以进行任意次操作,每次操作是将一行或一列的数都取反,问你最多可以得到多少个1? $n\le 20,m\le ...

  8. D1. Kirk and a Binary String (easy version)

    D1. Kirk and a Binary String (easy version) 01串找最长不降子序列 给定字符串s,要求生成一个等长字符串t,使得任意l到r位置的最长不降子序列长度一致 从后 ...

  9. CF662C Binary Table【FWT】

    CF662C Binary Table 题意: 给出一个\(n\times m\)的\(01\)矩阵,每次可以反转一行或者一列,问经过若干次反转之后,最少有多少个\(1\) \(n\le 20, m\ ...

随机推荐

  1. Nginx解决前端访问资源跨域问题

    被前端跨域问题折磨快2天后,终于用ngnx的方式解决了,所以在此总结下. 该篇只探讨如何用Ngnx解决跨域问题,对于原理不作讨论. 1.首先介绍Windows环境下Nignx的相关命令操作 nginx ...

  2. SIGGRAPH Asia 2020 电脑动画节(CAF)获奖短片出炉!

    电脑动画节(CAF) 是SIGGRAPH Asia盛会最受瞩目的环节之一.2020年12月15日,SIGGRAPH Asia 2020虚拟线上会议正式宣布了电脑动画节的三部获奖短片:最佳作品奖< ...

  3. MySQL 设置保留几天的binlog

    1 ) 查看默认的日志保存天数: mysql> show variables like 'expire_logs_days'; +------------------+-------+ | Va ...

  4. 深入汇编指令理解Java关键字volatile

    volatile是什么 volatile关键字是Java提供的一种轻量级同步机制.它能够保证可见性和有序性,但是不能保证原子性 可见性 对于volatile的可见性,先看看这段代码的执行 flag默认 ...

  5. /etc/hosts导致的问题

    今天安装完成orzdba之后,执行./orzdba -l 报如下错误: Usage: Socket::inet_ntoa(ip_address_sv) at /var/lib/mysql/trunk/ ...

  6. mysql中的kill

    show processlist;查看id, 然后 kill id ; 就行了.

  7. 物理STANDBY库创建还原点(打开为read write后再变回主库)

    开启STANDBY库为READ WRITE 1.取消主库传送归档 SQL> alter system set log_archive_dest_state_2=defer; 2.取消备库应用日志 ...

  8. oracle move表空间(分区表,索引)

    1.修改分区表分区表空间 SELECT 'ALTER TABLE ' || table_owner || '.' || TABLE_NAME || ' MOVE PARTITION ' || PART ...

  9. 容器编排系统K8s之包管理器helm基础使用(二)

    前文我们介绍了helm的相关术语和使用helm安装和卸载应用,回顾请参考:https://www.cnblogs.com/qiuhom-1874/p/14305902.html:今天我们来介绍下自定义 ...

  10. DockerFile关键字相关作用以及解释

    Dockerfile 关键字 作用 备注 FROM 指定父镜像 指定dockerfile基于那个image构建 MAINTAINER 作者信息 用来标明这个dockerfile谁写的 LABEL 标签 ...