题解:AT_abc377_c [ABC377C] Avoid Knight Attack
题目传送门
题目大意
有一个
例如,放在
有多少个不会被马吃掉的棋子?
题目分析
我们发现,这道题目是前一题的加强版,可以用二维数组记录被马吃掉的位置。
但是,我们发现
于是,我们想到,利用 map 记录下所有能被马攻击的坐标 (包括马所在位置),最后进行计算即可。
最坏空间复杂度
空间复杂度: 对于一个存储
M 个元素的双下标 map,每个位置有3 个元素,空间复杂度为\mathcal{O}(M) 。时间复杂度为
\mathcal{O}(M \log_2M) 。
我们可以打出八个方向的表,边输入边记录排除的格子。
:::warning[注意]{open}
- 要开 long long;
- 需要特判所记录格子坐标是否越界;
- 需要记录马的所在位置。 :::
具体介绍请看代码中的注释。
代码实现
#include <bits/stdc++.h>
#define int long long
using namespace std;
map <pair <int, int>, bool> a; // 记录(x, y)位置放置棋子,是否能被马吃掉
int n, m, x, y;
int fx[] = {0, 2, 1, -1, -2, -2, -1, 1, 2}; // 打8个方向的表
int fy[] = {0, 1, 2, 2, 1, -1, -2, -2, -1};
signed main() {
cin >> n >> m;
for (int i = 1;i <= m;i++) {
cin >> x >> y;
a[make_pair(x, y)] = 1; // 注意:马的所在位置也是不可放置的
for (int j = 1;j <= 8;j++) // 枚举8个方向
if (x + fx[j] > 0 && y + fy[j] > 0 && x + fx[j] <= n && y + fy[j] <= n) // 特判:防止坐标越界
a[make_pair(x + fx[j], y + fy[j])] = 1; // 将这个位置设为可被吃掉
}
// 进行数学运算:所有格子-可攻击格子=剩余格子,a.size()代表 map 中被使用过的格子数
cout << n * n - a.size() << endl;
return 0;
}
update 2024.11.4:
- 对于时空复杂度的计算做详细介绍。
update 2025.07.29:
- 由于洛谷编辑器更新,优化题解格式;
- 优化了时空复杂度计算,删除了常数部分。
update 2026.07.29:
- 删除了大量重复内容,修改表述。