📅  最后修改于: 2023-12-03 15:21:40.503000             🧑  作者: Mango
在二维平面上,有N个点 $P_1, P_2, \cdots, P_N$。对于每一对点 $P_i$ 和 $P_j$,定义它们之间的锤击距离为:$|x_i-x_j| + |y_i-y_j|$。现在,请你计算出所有点两两之间的锤击距离之和。
对于每一个点 $P_i$,我们可以求出它和其它所有点的横纵坐标之和,然后将它们相加即可得到答案。具体地,假设点 $P_i$ 的横坐标为 $x_i$,纵坐标为 $y_i$,则点 $P_i$ 和点 $P_j$ 之间的锤击距离为:
$$|x_i-x_j|+|y_i-y_j|=(x_i-x_j)+(y_i-y_j)+2\max(x_i-x_j, x_j-x_i, y_i-y_j, y_j-y_i)$$
因此,我们可以将所有点按照横坐标和纵坐标分别升序排序,在排序后的序列中,对于点 $P_i$,它与之前的点的锤击距离为:
$$\begin{aligned} & (x_i-x_{i-1}) + (y_i-y_{i-1}) + 2 \max { x_i-x_{i-1}, x_{i-1}-x_i, y_i-y_{i-1}, y_{i-1}-y_i } \ = & 2(x_i+y_i) - 2(x_{i-1}+y_{i-1}) + \max { x_i+x_{i-1}+y_i+y_{i-1}, x_i+x_{i-1}-y_i-y_{i-1}, \ & -x_i+x_{i-1}+y_i+y_{i-1}, -x_i+x_{i-1}-y_i-y_{i-1} } \end{aligned} $$
我们可以对上述式子进行预处理,将它们存放到两个数组 $a$ 和 $b$ 中。那么,所有 $P_i$ 和 $P_j$ 之间的锤击距离之和即为:
$$\sum_{i=1}^N\sum_{j=1,j\neq i}^N a_i+b_j$$
int n, x[N], y[N];
ll a[N], b[N]; // 存放 a_i 和 b_i
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &x[i], &y[i]);
}
sort(x+1, x+n+1); // 按 x 坐标升序排序
sort(y+1, y+n+1); // 按 y 坐标升序排序
for (int i = 2; i <= n; i++) {
a[i] = a[i-1] + 2LL * (x[i] + y[i]) - 2LL * (x[i-1] + y[i-1]);
}
for (int i = n-1; i >= 1; i--) {
b[i] = b[i+1] + 2LL * (x[i] + y[i]) - 2LL * (x[i+1] + y[i+1]);
}
ll ans = 0;
for (int i = 1; i < n; i++) {
ans += a[i] + b[i+1];
}
printf("%lld\n", ans);
return 0;
}
以上是C++的实现代码,时间复杂度为 $O(N\log N)$。