题解 P3964 松鼠聚会
一道有趣的题OwO
题意简述:在
然而题面只告诉了我们「一个点到周围的八个点距离为 1」,这种距离计量方式是啥意思呢。其实,这就是 切比雪夫距离 的定义,也称为 棋盘距离。
若二个向量或二个点 p、and q,其坐标分别为
这也等于以下
因此切比雪夫距离也称为
以数学的观点来看,切比雪夫距离是由一致范数(或称为上确界范数)所衍生的度量,也是超凸度量的一种。
在平面几何中,若二点 p 及 q 的直角坐标系坐标为
总结一下,切比雪夫距离指的是两个点各座标数值差的最大值,也就是
举个例子:
切比雪夫距离是常用的距离表示方式之一,这里同时介绍一下其他的距离表示方法。
-
欧几里得距离
初中数学教材介绍的两点间距离表示。
设
A(x_1,y_1),B(x_2,y_2) 那么|AB|=\sqrt{(x_2-x_1)^2+(y_2-y_1)^2} 一般模型:在一个坐标系上,求从一个点到另一个点的最短几何距离。
-
曼哈顿距离
二维空间内,两个点之间的曼哈顿距离为它们横坐标之差的绝对值与纵坐标之差的绝对值之和。它可以很快求出各点距离和。
即
A(x_1,y_1),B(x_2,y_2) 那么|AB|=|x_2-x_1|+|y_2-y_1| 一般模型:网格图中从一个点走向另一个点的最短距离。
-
切比雪夫距离
详细解释可参见上文维基百科的选段。
通俗的讲,有
A(x_1,y_1),B(x_2,y_2) ,那么切比雪夫距离定义为\max(|x_2-x_1|,|y_2-y_1|) 一般模型:棋盘上或者在图中一个点到另外相邻八个点的距离为 1。
现在我们已知了题目的询问原来是求 切比雪夫距离 的和,可是貌似没啥用啊。
考虑枚举每一个点,都要穷举其他
经过观察可以发现,切比雪夫距离
由于计算每个点取 max 复杂度跑不掉了,可不可以考虑向曼哈顿距离转化呢?(曼哈顿距离的优势马上就要展现出来了
尝试一下。康康分类讨论曼哈顿距离的公式可不可以化开。
哇哦,这个和
推广到更一般的情况,给出 曼哈顿 意义下的坐标
反过来,我们也能通过 切比雪夫 意义下的坐标
这个具体有什么用呢?上文已提到了曼哈顿距离求和非常快的优势,现在我们再研究研究怎么个快速求和。
还是从根式推起。
设
以
如果先将横坐标处理为递增的,很容易得知柿子
这玩意..
不就是前缀和嘛..?
维护有序状态下 j * xj 算就行了。
#include <iostream>
#include <algorithm>
#include <climits>
#include <stdio.h>
#define MAXN 100010
typedef long long i64;
int n, x[MAXN], y[MAXN], gx[MAXN], gy[MAXN];
i64 sumx[MAXN], sumy[MAXN];
inline i64 calc(int i)
{
int rx = std::lower_bound(gx + 1, gx + n + 1, x[i]) - gx;
int ry = std::lower_bound(gy + 1, gy + n + 1, y[i]) - gy;
return rx * 1LL * x[i] - sumx[rx] + sumx[n] - sumx[rx] - (n - rx) * 1LL * x[i] +
ry * 1LL * y[i] - sumy[ry] + sumy[n] - sumy[ry] - (n - ry) * 1LL * y[i];
/*
rx: 在 gx[] 中 x 排多少位,即 gx[i] = x 的 i
ry: 在 gy[] 中 y 排多少位,即 gy[i] = y 的 i
只有找到了 rx 和 ry 才能分成两步计算,rx 和 ry 也是下文两个数组下的 “j”
dis(1, j) + dis(2, j) + ... + dis(j, j) + ... + dis(n, j) 为把 j 这个点设为终点的曼哈顿距离,坐标已经转为曼哈顿意义下的坐标
排序后分为 j 之前和 j 之后两部分计算
有序 x[] 下 x 坐标的贡献:
rx 之前为 rx * x[j] - sum(x[1..j])
rx 之后为 sum(x[j..n]) - (n - (j + 1) + 1) * x[j]
y 坐标同理
答案的柿子建议自己写,也可以把 * 1LL * y[i] 替换成 * 1LL * gy[ry]
*/
}
signed main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
int xi, yi;
scanf("%d%d", &xi, &yi);
x[i] = gx[i] = xi + yi;
y[i] = gy[i] = xi - yi;
/*
转化成曼哈顿意义下坐标
gx[] gy[] 是要经过排序得到的有序数组
x[] y[] 存第 i 个点坐标
*/
}
std::sort(gx + 1, gx + n + 1);
for(int i = 1; i <= n; ++i)
sumx[i] = sumx[i - 1] + gx[i];
std::sort(gy + 1, gy + n + 1);
for(int i = 1; i <= n; ++i)
sumy[i] = sumy[i - 1] + gy[i];
/*
计算前缀和
为了维护 sum(gx[1..j]) 和 sum(gy[1..j])
j 是文章中提到的 x_j 的下标
*/
static i64 res = LLONG_MAX;
for(int i = 1; i <= n; ++i)
res = std::min(res, calc(i));
//最后记得 div 2
printf("%lld\n", res >> 1LL);
return 0;
}
由于柿子比较多,很可能打错,代码中的注释有的是写代码时写的,可能和文章中的解释有些出入(主要是下标
这篇题解花了我很长时间,马上要 CPS-S 了,祝大家 RP++