当前位置: 首页 > news >正文

A - 2x2 Erasing

题目位置:

点这里: https://atcoder.jp/contests/arc205/tasks/arc205_a
本专栏提供了整个比赛的题解: link

题目意思翻译

题目描述

首先我们考虑一个 NNNNNN 列的矩阵,我们将 (r,c)(r, c)(r,c) 中的 rrr 记作行,ccc 记作列。矩阵的每个位置都有一个颜色,有黑色和白色两种,我们将黑色记作 #, 将白色记作 .

您会收到 QQQ 个有关此网格的问题,因此请逐一回答。在第 i(1≤i≤Q)i(1 \le i \le Q)i(1iQ)个问题中,给出了整数Ui,Di,Li,RiU_i, D_i, L_i, R_iUi,Di,Li,Ri,请回答每个问题的答案。

在对所有不满足 Ui≤r≤DiU_i \le r \le D_iUirDi Li≤c≤RiL_i \le c \le R_iLicRi 的位置 (r,c)(r, c)(r,c) 进行着色黑色后, 将以下操作连续执行最多次数。

选择一对整数 (r,c)(r, c)(r,c) 要求 (r,c),(r,c+1),(r+1,c),(r+1,c+1)(r, c), (r, c + 1), (r + 1, c), (r + 1, c + 1)(r,c),(r,c+1),(r+1,c),(r+1,c+1) 全是白色,然后将他们其中一个染成黑色。

独立解决每个问题。换句话说,每个单元格的颜色都重置为每个问题的初始状态。

数据范围

2≤N≤5002 \le N \le 5002N500
1≤Q≤1051 \le Q \le 10^51Q105
Sr,cS_{r, c}Sr,c#. 其中之一
1≤Ui<Di≤N1 \le U_i < D_i \le N1Ui<DiN
1≤Li<Ri≤N1 \le L_i < R_i \le N1Li<RiN
本题输入全部为整数

输入格式

输入第一行是一个整数 NNNQQQ
第二行到第 N+1N+1N+1 行,每行 NNN 个字符,表示输入一个矩阵 SSS
N+2N+2N+2 行到 N+1+QN + 1 + QN+1+Q 行,每行输入四个整数 Ui,Di,Li,RiU_i,D_i,L_i,R_iUi,Di,Li,Ri

输出格式

输出 QQQ 行,每行表示第 iii 个问题的答案

输入样例1

5 4
..#.#
.....
#....
...#.
.#...
1 3 1 3
3 5 3 5
2 3 1 4
1 5 1 5

输出样例1

2
0
2
5

输入样例2

7 6
#.#....
.....#.
.......
.#..#.#
#....#.
.......
....##.
1 3 2 7
4 6 1 6
6 7 2 7
3 5 4 6
1 6 2 4
1 7 1 7

输出样例2

4
4
2
0
6
13

思路

这道题一看就 没有思路 很神奇。

我们发现题目要将输入的矩阵构造成一个新的矩阵,但是 NNN 可能高达 500500500 如果每个询问都是使用构造法,那么我们发现时间复杂度是 O(n2)O(n^2)O(n2),但是 qqq 可能达到 10510^5105 如果使用构造法就算再怎么优化,也是不可行的

因为时间复杂度到达了 O(n2×q)O(n^2 \times q)O(n2×q) 最坏为 500×500×105=2.5×1010500 \times 500 \times 10^5 = 2.5 \times 10^{10}500×500×105=2.5×1010
已经超过了 10810^8108 不可行 。

但是暴力不可行,但是我们可以通过暴力找规律,
我们首先制造一个输出将矩阵改为题目输入的矩阵的代码

#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define REP(i, a, b) for (int i = (a); i <= (b); i++)int n, q;
char Map[512][512];
char tmp[512][512];void solve(int u1, int d1, int l1, int r1)
{REP(i, 1, n) {REP(j, 1, n) { tmp[i][j] = Map[i][j];if (i < u1 || i > d1 || j < l1 || j > r1) tmp[i][j] = '#';putchar(tmp[i][j]);}putchar('\n');}
}

当输入为样例 1 中的 1 3 1 3 时,我们发现代码输出了

..###
...##
#..##
#####
#####

作者在比赛的时候发现了如下的规律。
因为题意是计算正方形的个数,我们不管修改,直接计算题目由.组成的正方形的个数。

我们发现有 2 个,和答案完全吻合,作者又测试了很多数据,都是这样的,这启示我们写下下面的代码:

#include <stdio.h>
#include <vector>
#include <algorithm>
#include <string>
#include <unordered_set>using namespace std;#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define REP(i, a, b) for (int i = (a); i <= (b); i++)typedef long long ll;int n, q;
char Map[512][512];
char tmp[512][512];void solve(int u1, int d1, int l1, int r1)
{REP(i, 1, n) REP(j, 1, n) { tmp[i][j] = Map[i][j];if (i < u1 || i > d1 || j < l1 || j > r1) tmp[i][j] = '#';}int cnt = 0;REP(i, 1, n) {REP(j, 1, n) if (tmp[i][j] == '.' && tmp[i][j + 1] == '.' && tmp[i + 1][j] == '.' && tmp[i + 1][j + 1] == '.') cnt++;}printf("%d\n", cnt);
}int main()
{scanf("%d %d\n", &n, &q);REP(i, 1, n) REP(j, 1, n) scanf(" %c", &Map[i][j]);while (q --) {int u1, d1, l1, r1;scanf("%d%d%d%d", &u1, &d1, &l1, &r1);solve(u1, d1, l1, r1);}return 0;
}

然后直接 TLE 了,但是正确了 555 个测试点,其它全部超时。
我们考虑改进这个代码,我们可以使用一次预处理,计算出每个位置的 2×22 \times 22×2 的正方形的个数.

这启示我们使用二维前缀和实现,首先一次预处理,再单次查询即可。
不会二维前缀和的点这里: link

代码:

作者连二位前缀和都调了很久

#include <stdio.h>
#include <vector>
#include <algorithm>
#include <string>using namespace std;#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define REP(i, a, b) for (int i = (a); i <= (b); i++)typedef long long ll;int n, q;
char Map[512][512];
char tmp[512][512];
int TmpCount[512][512];void solve(int u1, int d1, int l1, int r1)
{
//	printf("%d %d %d %d\n", TmpCount[d1][r1], TmpCount[r1][l1], TmpCount[u1][d1], TmpCount[u1][l1]);printf("%d\n", TmpCount[d1][r1] - TmpCount[d1][l1] - TmpCount[u1][r1] + TmpCount[u1][l1]);
}int main()
{scanf("%d %d\n", &n, &q);REP(i, 1, n) REP(j, 1, n) scanf(" %c", &Map[i][j]);REP(i, 1, n) REP(j, 1, n) {TmpCount[i][j] = TmpCount[i - 1][j] + TmpCount[i][j - 1] - TmpCount[i - 1][j - 1];if (Map[i - 1][j - 1] == '.' && Map[i][j - 1] == '.' && Map[i - 1][j] == '.' && Map[i][j] == '.') TmpCount[i][j] ++;
//    	printf("i = %d j = %d Count[i][j] = %d\n", i, j, TmpCount[i][j]);}while (q --) {int u1, d1, l1, r1;scanf("%d%d%d%d", &u1, &d1, &l1, &r1);solve(u1, d1, l1, r1);}return 0;
}

时间复杂度分析

AC 代码的时间复杂度为预处理 O(n2)O(n^2)O(n2) 单词查询为 O(1)O(1)O(1)

所以这个代码的时间复杂度为 O(n2+q)O(n^2 + q)O(n2+q) 完全可行


文章转载自:

http://MA7y3YlM.cbndj.cn
http://mTnwONnd.cbndj.cn
http://0SeDMP4X.cbndj.cn
http://YgoCv159.cbndj.cn
http://jvJmjnbW.cbndj.cn
http://nIexpmE8.cbndj.cn
http://Df1mrEEu.cbndj.cn
http://Zh3eOFg7.cbndj.cn
http://guNAUdgi.cbndj.cn
http://CeS8cPa8.cbndj.cn
http://ak8sac05.cbndj.cn
http://ngBda3kQ.cbndj.cn
http://6W6ZlySj.cbndj.cn
http://6x2S9T5h.cbndj.cn
http://lYhAMigz.cbndj.cn
http://oLduHaCn.cbndj.cn
http://87fZXloX.cbndj.cn
http://QAgP6n2L.cbndj.cn
http://TlE86C9C.cbndj.cn
http://w1mZl2RV.cbndj.cn
http://n9O3xokN.cbndj.cn
http://v9ARA9ea.cbndj.cn
http://1zbWPPwH.cbndj.cn
http://eLrD06nn.cbndj.cn
http://dC8VWdlg.cbndj.cn
http://imHyz604.cbndj.cn
http://L4nIc04A.cbndj.cn
http://hrfJ0Zoh.cbndj.cn
http://grZqtIar.cbndj.cn
http://ut48MNbv.cbndj.cn
http://www.dtcms.com/a/372564.html

相关文章:

  • 栈欺骗技术的作用是什么?
  • 细说分布式ID
  • nginx自动剔除与恢复
  • tmi8150B控制ir_cut
  • 【期末复习】嵌入式——S5PV210开发板
  • 基于brpc的轻量级服务注册中心设计与实现
  • 作用域報錯
  • 代码随想录学习摘抄day7(二叉树11-21)
  • 固态硬盘——M.2接口技术
  • 数字化浪潮下,传统加工厂如何智能化转型?
  • Miniflux – RSS 订阅
  • Nginx主配置文件
  • 架构进阶——解读121页IT规划咨询项目规划报告【附全文阅读】
  • 大模型显存占用量换算
  • Compose笔记(五十)--stickyHeader
  • WebGIS三维可视化 + 数据驱动:智慧煤仓监控系统如何破解煤炭仓储行业痛点
  • 刷题集(1)
  • 别墅装修的价钱如何估算?
  • Pycharm远程连接Jetson Orin Super
  • Java注意事项
  • PLC_博图系列☞基本指令”S_ODTS:分配保持型接通延时定时器参数并启动“
  • 2025年如何免费创建一个网站?
  • Linux驱动开发(1)概念、环境与代码框架
  • 3种XSS攻击简单案例
  • Windows存储IOPS的预测性扩容
  • 模式组合应用-装饰器模式
  • 【数据结构与算法Trip第1站】基本介绍
  • Dockerfile解析器指令(Parser Directive)指定语法版本,如:# syntax=docker/dockerfile:1
  • Docker命令(全)
  • 【基于yolo和web的垃圾分类系统】