CF-1440C2 Binary Table (Hard Version) (构造,模拟)
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个一组进行处理。分情况讨论
- 如果 4 个都是 ‘1’ ,进行一次翻转,只留右下角的 1,这个 1 留到最后处理
- 如果有某 3 个是 ‘1’ ,那么一次操作可以搞定
- 如果有某 2 个是 '1',那么可以细分为两种情况,这两种情况都可以用两步解决
- 如果只有 1 个是 '1',那么留作最后考虑。
根据上面的情况,对最后两行进行处理,如果 \(m\) 是偶数,刚好可以处理完。但如果 \(m\) 是奇数,那么对于最后一列的两个格子,我们需要特殊考虑。
可以想到,我们按照 4 个一组处理完左边四个之后,最多只会在 (n,m-1)
这个位置留一个 1,那么不论第 m 列是什么情况,我们都可以在两步操作内,将他们变为0。这个操作是绝对保险的。
最后,只剩下最后两行的某些单独的 1 了,这些单独的 1 可以在 3 步内消除,至于为什么这么操作不会使得操作次数爆炸,可以从这些 1 的产生来源考虑。
这个 1 原本就摆在这里,那么旁边 3 个空位之前是没有操作过的,这就给这个 1 留下了多余的操作空间。
这个 1 是消了 3 个之后剩下的,那么消除那 3 个用了一次,消除单独的 1 用了 3 次,刚好四次。
对于 m 为奇数时,最右边一列中单独的 1,这个虽然也需要使用 3 步,但是由于此时 m-1 列都是空的,这得多亏左边那四个之前是消除干净了的。而 4 个一组消除干净最多只需要两步,所以这种情况也是保险的。
#include <bits/stdc++.h>
using namespace std;
const int N = 101;
int T, n, m, t[N][N];
char s[N][N];
vector<pair<int,int> > v;
void add(int x, int y){
v.push_back({x, y});
t[x][y] ^= 1;
}
void add(int x, int y, int p){
if(p == 0) add(x, y);
else if(p == 1) add(x, y+1);
else if(p == 2) add(x+1, y);
else if(p == 3) add(x+1, y+1);
}
void solve(int x, int y){
int c0 = t[x][y];
int c1 = t[x][y+1];
int c2 = t[x+1][y];
int c3 = t[x+1][y+1];
int c = c0 + c1 + c2 + c3;
if(c == 4) {
add(x, y, 0);
add(x, y, 1);
add(x, y, 2);
} else if(c == 3) {
if(c0 == 0) add(x, y, 1), add(x, y, 2), add(x, y, 3);
if(c1 == 0) add(x, y, 0), add(x, y, 2), add(x, y, 3);
if(c2 == 0) add(x, y, 0), add(x, y, 1), add(x, y, 3);
if(c3 == 0) add(x, y, 0), add(x, y, 1), add(x, y, 2);
} else if(c == 2){
if(c0 && c1) {
add(x, y, 0);add(x, y, 2);add(x, y, 3);
add(x, y, 1);add(x, y, 2);add(x, y, 3);
} else if(c0 && c2) {
add(x, y, 0);add(x, y, 1);add(x, y, 3);
add(x, y, 2);add(x, y, 1);add(x, y, 3);
} else if(c0 && c3) {
add(x, y, 0);add(x, y, 1);add(x, y, 2);
add(x, y, 3);add(x, y, 1);add(x, y, 2);
} else if(c1 && c2){
add(x, y, 1);add(x, y, 0);add(x, y, 3);
add(x, y, 2);add(x, y, 0);add(x, y, 3);
} else if(c1 && c3) {
add(x, y, 1);add(x, y, 0);add(x, y, 2);
add(x, y, 3);add(x, y, 0);add(x, y, 2);
} else if(c2 && c3) {
add(x, y, 2);add(x, y, 0);add(x, y, 1);
add(x, y, 3);add(x, y, 0);add(x, y, 1);
}
}
}
int main(){
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
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++){
t[i][j] = s[i][j] - '0';
}
}
for(int i=1;i<=n-2;i++){
for(int j=1;j<=m;j++){
if(t[i][j] == 0) continue;
add(i, j); add(i+1, j);
if(j == m) add(i+1, j-1);
else add(i, j+1);
}
}
for(int j = 1; j + 1 <= m; j += 2){
solve(n - 1, j);
}
if(m & 1) solve(n - 1, m - 1);
// 处理倒数第二行中单着的
for(int j = 1; j <= m; j++){
if(t[n-1][j] == 0) continue;
if(j == m) {
add(n-1, j-1, 1); add(n-1, j-1, 0); add(n-1, j-1, 3);
add(n-1, j-1, 0); add(n-1, j-1, 2); add(n-1, j-1, 1);
add(n-1, j-1, 3); add(n-1, j-1, 2); add(n-1, j-1, 1);
} else {
add(n-1, j, 0); add(n-1, j, 1); add(n-1, j, 2);
add(n-1, j, 2); add(n-1, j, 0); add(n-1, j, 3);
add(n-1, j, 1); add(n-1, j, 0); add(n-1, j, 3);
}
}
// 处理倒数第一行单着的
for(int j = 1; j <= m; j++){
if(t[n][j] == 0) continue;
if(j == m) {
add(n-1, j-1, 3); add(n-1, j-1, 2); add(n-1, j-1, 1);
add(n-1, j-1, 2); add(n-1, j-1, 0); add(n-1, j-1, 3);
add(n-1, j-1, 1); add(n-1, j-1, 0); add(n-1, j-1, 3);
} else {
add(n-1, j, 2); add(n-1, j, 0); add(n-1, j, 3);
add(n-1, j, 0); add(n-1, j, 1); add(n-1, j, 2);
add(n-1, j, 3); add(n-1, j, 1); add(n-1, j, 2);
}
}
cout << v.size() / 3 << endl;
for(int i=0;i<v.size();){
#define x first
#define y second
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);
i += 3;
}
v.clear();
}
return 0;
}
CF-1440C2 Binary Table (Hard Version) (构造,模拟)的更多相关文章
- 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 ...
- CF 662C Binary Table
用FWT优化计算. 首先发现行数很小,想到一个暴力的方法,就是以一个二进制位$0$表示这一行不翻转而二进制位$1$表示这一行翻转,然后$2^n$枚举出所有行的翻转情况,再$O(m)$计算所有的结果. ...
- 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 ...
- 【CF662C】Binary Table(FWT)
[CF662C]Binary Table(FWT) 题面 洛谷 CF 翻译: 有一个\(n*m\)的表格(\(n<=20,m<=10^5\)), 每个表格里面有一个\(0/1\), 每次可 ...
- [CF662C Binary Table][状压+FWT]
CF662C Binary Table 一道 FWT 的板子-比较难想就是了 有一个 \(n\) 行 \(m\) 列的表格,每个元素都是 \(0/1\),每次操作可以选择一行或一列,把 \(0/1\) ...
- 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 ...
- 【CF662C】Binary Table 按位处理
[CF662C]Binary Table 题意:给你一个$n\times m$的01网格,你可以进行任意次操作,每次操作是将一行或一列的数都取反,问你最多可以得到多少个1? $n\le 20,m\le ...
- D1. Kirk and a Binary String (easy version)
D1. Kirk and a Binary String (easy version) 01串找最长不降子序列 给定字符串s,要求生成一个等长字符串t,使得任意l到r位置的最长不降子序列长度一致 从后 ...
- CF662C Binary Table【FWT】
CF662C Binary Table 题意: 给出一个\(n\times m\)的\(01\)矩阵,每次可以反转一行或者一列,问经过若干次反转之后,最少有多少个\(1\) \(n\le 20, m\ ...
随机推荐
- 人生苦短我用Python,本文助你快速入门
目录 前言 Python基础 注释 变量 数据类型 浮点型 复数类型 字符串 布尔类型 类型转换 输入与输出 运算符 算术运算符 比较运算符 赋值运算符 逻辑运算符 if.while.for 容器 列 ...
- 改进你的c#代码的5个技巧(三)
本文完全独立于前两篇文章.如果你喜欢它们,我希望你也会喜欢这个.在上一篇文章中,我展示了哪种方法更快,并比较了代码的执行速度.在本文中,我将展示不同代码片段的内存消耗情况.为了显示内存映射和分配图,我 ...
- 【剑指 Offer】11.旋转数组的最小数字
题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的 ...
- 【SpringBoot1.x】SpringBoot1.x 日志
SpringBoot1.x 日志 日志框架 市面上有很多日志框架,一个日志框架一般包括抽象层和实现. SpringBoot,它的底层是 Spring,而 Spring 框架默认是用 JCL(java. ...
- 【SpringBoot1.x】SpringBoot1.x 配置
SpringBoot1.x 配置 文章源码 配置文件 SpringBoot 使用一个全局的配置文件,配置文件名是固定的. application.properties.application.yml都 ...
- N叉树的最大深度-DFS
再看这道题之前,先来一道类似的简单题. 题目:求二叉树的最大深度 给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. 说明: 叶子节点是指没有子节点的节点. 示 ...
- Linux 安装分区设置分区大小
一.Linux分区挂载点介绍 Linux分区挂载点介绍,推荐容量仅供参考不是绝对,跟各系统用途以及硬盘空间配额等因素实际调整: 分区类型 介绍 备注 /boot 启动分区 一般设置100M-200M, ...
- 【Android初级】如何动态添加菜单项(附源码+避坑)
我们平时在开发过程中,为了灵活多变,除了使用静态的菜单,还有动态添加菜单的需求.今天要分享的功能如下: 在界面的右上角有个更多选项,点开后,有两个子菜单:关于和退出 点击"关于", ...
- 温习数据算法—js滑块验证码
前言 大多数的应用软件都需要输入一些验证码,验证码的样式也多种多样. 比如抢票,提交订单需要验证码,很多人就纳闷了,怎么还需要验证码呢?这不是浪费时间嘛. 存在即合理,合理就是现实的. 源码下载地址+ ...
- Linux、JDK、Netty中的NIO与零拷贝
一.先理解内核空间与用户空间 Linux 按照特权等级,把进程的运行空间分为内核空间和用户空间,分别对应着下图中, CPU 特权等级分为4个,Linux 使用 Ring 0 和 Ring 3. 内核空 ...