学习笔记_25_03_14

学习笔记_25_03_14

Reference

P3913 车的攻击

题目描述

N×NN \times N 的国际象棋棋盘上有KK 个车,第ii个车位于第RiR_i行,第CiC_i 列。求至少被一个车攻击的格子数量。

车可以攻击所有同一行或者同一列的地方。

输入格式

第1 行,2 个整数N,KN,K

接下来K 行,每行2 个整数Ri,CiR_i,C_i

输出格式

1 个整数,表示被攻击的格子数量。

输入输出样例 #1

输入 #1

1
2
3
3 2
1 2
2 2

输出 #1

1
7

说明/提示

• 对于30% 的数据,1N103;1K1031 \le N \le 10^3; 1 \le K \le 10^3

• 对于60% 的数据,1N106;1K1061 \le N \le 10^6; 1 \le K \le 10^6

• 对于100% 的数据,1N109;1K106;1Ri,CiN1 \le N \le 10^9; 1 \le K \le 10^6; 1 \le R_i , C_i \le N

解决方案

笔者的第一版代码是在硬抗庞大的数据规模的情况下头铁按照模拟棋盘的思路写出的,因此喜提10分…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if __name__ == "__main__":
n, k = map(int, input().split())
cars = []
for i in range(k):
x, y = map(int, input().split())
cars.append((x, y))

# 创建棋盘
Map = [[0 for i in range(n)] for i in range(n)]

for x, y in cars:
for i in range(n):
Map[x][i] += 1
Map[i][y] += 1

count = 0
for i in range(n):
for j in range(n):
if Map[i][j] != 0:
count += 1

print(count)

因此显然这道题需要换一种角度思考,不妨就按Reference中题解给出的思路去理解。即使在不向一个方向平移的情况下,我们依旧能够想象出其盲区的小格子的大致样子。与其尝试移动,不如尝试将所有的零碎小格子拼成一块矩形,其面积与棋盘面积的差就是我们所要的答案。

两个相同的x值或y值显然只能对同一列造成影响,那么我们只需要统计一共有多少种不同的x值和y值即可。

那么最后要求的答案即为n * n - (n - count_x) * (n - count_y)

c++题解如下所示(Python版本似乎由于语言的限制还是会爆TLE):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <algorithm>
using namespace std;

const int K = 1000010;

long long xs[K], ys[K];

int main()
{
long long n, k;
cin >> n >> k;

for (int i = 0; i < k; i++)
{
cin >> xs[i] >> ys[i];
}

// 开始计算坐标中不重复的点的个数
sort(xs, xs + k);
sort(ys, ys + k);

long long count_x = 0, count_y = 0;

for (int i = 0; i < k; i++)
{
if (xs[i] != xs[i+1])
{
count_x++;
}
if (ys[i] != ys[i+1])
{
count_y++;
}
}

long long count = n * n - (n - count_x) * (n - count_y);
cout << count;

return 0;
}

学习笔记_25_03_14
http://example.com/2025/03/14/note07/
作者
谢斐
发布于
2025年3月14日
许可协议