洛谷 P3964 松鼠聚会

4 篇文章 0 订阅
3 篇文章 0 订阅

题目链接

参考链接

题解:

这道题目的距离其实就是切比雪夫距离,又称棋盘距离,也就是 D = m a x ( ∣ x 2 − x 1 ∣ , ∣ y 2 − y 1 ∣ ) D = max(|x_2-x_1|,|y_2-y_1|) D=max(x2x1,y2y1)。与之有一定联系的距离是曼哈顿距离,假设 A ( x 1 , y 1 ) , B ( x 2 , y 2 ) A(x_1,y_1),B(x_2,y_2) A(x1,y1),B(x2,y2),那么 ∣ A B ∣ = ∣ x 2 − x 1 ∣ + ∣ y 2 − y 1 ∣ |AB|=|x_2-x_1|+|y_2-y_1| AB=x2x1+y2y1

我们将曼哈顿距离化开:

D = ∣ x 2 − x 1 ∣ + ∣ y 2 − y 1 ∣ = m a x ( x 2 − x 1 + y 2 − y 1 , x 1 − x 2 + y 2 − y 1 , x 1 − x 2 + y 1 − y 2 , x 2 − x 1 + y 1 − y 2 ) = m a x { ∣ ( x 2 + y 2 ) − ( x 1 + y 1 ) ∣ ,   ∣ ( x 2 − y 2 ) − ( x 1 − y 1 ) ∣ } D=|x_2-x_1|+|y_2-y_1|=max(x_2-x_1+y_2-y_1,x_1-x_2+y_2-y_1,x_1-x_2+y_1-y_2,x_2-x_1+y_1-y_2)=max\{|(x_2+y_2)-(x_1+y_1)|,\ |(x_2-y_2)-(x_1-y_1)|\} D=x2x1+y2y1=max(x2x1+y2y1,x1x2+y2y1,x1x2+y1y2,x2x1+y1y2)=max{(x2+y2)(x1+y1), (x2y2)(x1y1)}

上面这个形式其实和切比雪夫距离 D c h e s s = m a x ( ∣ x 2 − x 1 ∣ , ∣ y 2 − y 1 ∣ ) D_{chess}=max(|x_2-x_1|,|y_2-y_1|) Dchess=max(x2x1,y2y1)形式上非常像,我们可以发现,曼哈顿意义下的 ( x 1 , y 1 ) ( x 2 , y 2 ) (x_1,y_1)(x_2,y_2) (x1,y1)(x2,y2)两点的距离转化为切比雪夫意义下的 ( x 2 + y 2 , x 2 − y 2 ) ( x 1 + y 1 , x 1 − y 1 ) (x_2+y_2,x_2-y_2)(x_1+y_1,x_1-y_1) (x2+y2,x2y2)(x1+y1,x1y1)两点的距离。

我们可以推广一下,给出曼哈顿意义下的坐标 ( x , y ) (x,y) (x,y),可以转化成切比雪夫意义下的坐标 ( x + y , x − y ) (x+y,x-y) (x+y,xy)

反过来,给了切比雪夫意义下的坐标 ( x , y ) (x,y) (x,y),可以转化成曼哈顿意义下的坐标 ( x + y 2 , x − y 2 ) (\frac{x+y}2,\frac{x-y}2) (2x+y,2xy)

有了上面这个转化怎么用呢?

我们现在假设 d i s ( i , j ) dis(i,j) dis(i,j)为曼哈顿意义下 i i i j j j的曼哈顿距离。如果当前的终点是 j j j,那么有 a n s = ∑ i = 1 n d i s ( i , j ) ans=\sum_{i=1}^ndis(i,j) ans=i=1ndis(i,j),这个要是求的话,复杂度是 O ( n 2 ) O(n^2) O(n2)。我们化简一下:

∑ i = 1 n d i s ( i , j ) = d i s ( 1 , j ) + d i s ( 2 , j ) + ⋯ + d i s ( n , j ) \sum_{i=1}^ndis(i,j)=dis(1,j)+dis(2,j)+\dots+dis(n,j) i=1ndis(i,j)=dis(1,j)+dis(2,j)++dis(n,j)

我们现在用 d i s ( i , j ) dis(i,j) dis(i,j)中的一部分 ∣ x i − x j ∣ |x_i-x_j| xixj举例化简:

∑ i = 1 n Δ x = ∣ x 1 − x j ∣ + ∣ x 2 − x j ∣ + ⋯ + ∣ x j − x j ∣ + ∣ x j + 1 − x j ∣ + ⋯ + ∣ x n − x j ∣ \sum_{i=1}^n\Delta x=|x_1-x_j|+|x_2-x_j|+\dots+|x_j-x_j|+|x_{j+1}-x_j|+\dots+|x_n-x_j| i=1nΔx=x1xj+x2xj++xjxj+xj+1xj++xnxj

我们将横坐标排序成递增,容易发现 ∣ x j − x j ∣ |x_j-x_j| xjxj之前的式子都可以拆掉绝对值化简; ∣ x j + 1 − x j ∣ |x_{j+1}-x_j| xj+1xj及以后的式子可以不用动,这样上面的式子就化简成:

= ∑ i = 1 j ( x j − x i ) + ∑ i = j + 1 n ( x i − x j ) =\sum_{i=1}^j(x_j-x_i)+\sum_{i=j+1}^n(x_i-x_j) =i=1j(xjxi)+i=j+1n(xixj)

这个式子可以发现就是前缀和。 d i s ( i , j ) dis(i,j) dis(i,j)中的 Δ y \Delta y Δy可以同理化简。

因此这道题目的整体思路就是:

读入切比雪夫意义下的坐标并化为曼哈顿坐标,坐标可以先不除以2,到最后将答案除以2也可以。

x , y x,y x,y分别排序为递增,并求出前缀和。

然后枚举终点,使用二分将 x i , y i x_i,y_i xi,yi在递增序列的位置找出,根据上面的式子,即可求出答案。

实现细节见代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
const int MAXN = 1e6 + 10;

int x[MAXN], y[MAXN], gx[MAXN], gy[MAXN], sumx[MAXN], sumy[MAXN], n;
int solve(int now) {
	int rx = lower_bound(gx + 1, gx + 1 + n, x[now]) - gx;
	int ry = lower_bound(gy + 1, gy + 1 + n, y[now]) - gy;
	int ans = rx * x[now] - sumx[rx] + sumx[n] - sumx[rx] - (n - rx) * x[now];
	ans += ry * y[now] - sumy[ry] + sumy[n] - sumy[ry] - (n - ry) * y[now];
	return ans;
} 
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++) {
		int x1, y1;
		cin >> x1 >> y1;
		x[i] = gx[i] = x1 + y1; // 这里不÷2,避免精度问题
		y[i] = gy[i] = x1 - y1;
	}
	sort(gx + 1, gx + 1 + n);
	sort(gy + 1, gy + 1 + n);
	for (int i = 1; i <= n; i++) {
		sumx[i] = sumx[i - 1] + gx[i];
		sumy[i] = sumy[i - 1] + gy[i];
	}
	int ans = 1e16;
	for (int i = 1; i <= n; i++) {
		ans = min(ans, solve(i));
	}
	cout << ans / 2 << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值