1 条题解
-
0
「OOI 2016 Day 1」守护者 题解
题目分析
我们有 个点 ,需要找出所有满足曼哈顿距离等于欧几里得距离的点对 。
关键推导
曼哈顿距离:
欧几里得距离:
要使 ,即:
$$|x_i - x_j| + |y_i - y_j| = \sqrt{(x_i - x_j)^2 + (y_i - y_j)^2} $$两边平方:
$$(|x_i - x_j| + |y_i - y_j|)^2 = (x_i - x_j)^2 + (y_i - y_j)^2 $$展开左边:
$$|x_i - x_j|^2 + |y_i - y_j|^2 + 2|x_i - x_j||y_i - y_j| = (x_i - x_j)^2 + (y_i - y_j)^2 $$由于 ,两边抵消后得到:
因此条件等价于:
即:
计数方法
设:
- 表示横坐标为 的点的数量
- 表示纵坐标为 的点的数量
- 表示点 出现的次数
那么:
- 横坐标相同的点对数量:
- 纵坐标相同的点对数量:
- 完全相同的点对数量:
根据容斥原理,最终答案为:
$$\text{答案} = \sum_{v} \binom{C_x[v]}{2} + \sum_{v} \binom{C_y[v]}{2} - \sum_{p} \binom{C_{xy}[p]}{2} $$复杂度分析
时间复杂度
- 使用
map存储计数: - 使用
unordered_map存储计数:(平均情况)
空间复杂度
- ,需要存储各坐标的出现频率
代码实现
#include <iostream> #include <map> #include <vector> using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int n; cin >> n; map<int, int> countX, countY; map<pair<int, int>, int> countXY; for (int i = 0; i < n; i++) { int x, y; cin >> x >> y; countX[x]++; countY[y]++; countXY[{x, y}]++; } long long ans = 0; for (auto& p : countX) { long long c = p.second; ans += c * (c - 1) / 2; } for (auto& p : countY) { long long c = p.second; ans += c * (c - 1) / 2; } for (auto& p : countXY) { long long c = p.second; ans -= c * (c - 1) / 2; } cout << ans << "\n"; return 0; }总结
本题的关键在于通过数学推导将距离相等条件转化为坐标相等条件,然后使用组合计数和容斥原理高效解决问题。算法在 的数据规模下可以高效运行。
- 1
信息
- ID
- 4882
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者