其他分享
首页 > 其他分享> > P3964 [TJOI2013]松鼠聚会 切比雪夫距离 转化 曼哈顿距离

P3964 [TJOI2013]松鼠聚会 切比雪夫距离 转化 曼哈顿距离

作者:互联网

题意:

求\(n\)个点的切比雪夫距离和值的最小值

切比雪夫距离:对于\(x_1,y_1,x_2,y_2\)定义两个点的切比雪夫距离为\(max(|x_1-x_2|,|y_1-y_2|)\)

范围&性质:\(1\le n\le 10^5,-10^9\le x,y \le 10^9\)

分析:

首先我们先来了解一个小结论:

枚举到\((0,0)\)点曼哈顿距离为1的点:

\((1,0),(0,1),(-1,0),(0,-1),(0.5,0.5),(0.5,-0.5),(-0.5,-0.5),(-0.5,0.5)\)

枚举到\((0,0)\)点切比雪夫距离为1的点:

\((0,1),(1,1),(-1,1),(-1,-1),(0,-1),(1,-1),(1,0),(-1,0)\)

将上述的点画在坐标系里可以得到两个正方形,且第二个是第一个向左旋转\(45^\circ\)后扩展2倍得到

由此我们可以推得

将一个点\((x,y)\)的坐标变为\((x+y,x−y)\)后,原坐标系中的曼哈顿距离 \(=\)新坐标系中的切比雪夫距离

将一个点\((x,y)\)的坐标变为\((\frac {x+y}2,\frac {x-y}2)\) 后,原坐标系中的切比雪夫距离 \(=\) 新坐标系中的曼哈顿距离


由以上结论我们可以将给定点的切比雪夫距离转化为曼哈顿距离,对于每一个点他的坐标变化为了\((gx,gy)\)

由于曼哈顿距离有一个优越的性质:可以快速求多个点到一个点的距离和值,所以我们对于新的点进行排序

记枚举的松鼠为\(k\),那么:

\[ans= \sum_{i=1}^n dis(i,k)=\sum_{i=1}^n[ \;|gx_i-gx_k| \;+\; |gy_i-gy_k|\; ] \]

化简得到

\[ans=|gx_1-gx_k|+|gx_2-gx_k| \dots + +|gx_n-gx_k|+|gy_1-gy_k|+|gy_2-gy_k|\dots +|gy_n-gy_k| \]

只要维护一下前缀和就可以将复杂度降到单次\(\omicron(1)\)

代码:

#include<bits/stdc++.h>

using namespace std;

namespace zzc
{
	const int maxn = 1e5+5;
	long long x[maxn],y[maxn],nx[maxn],ny[maxn];
	long long sumx[maxn],sumy[maxn];
	long long ans,n;
	
	long long calc(long long i)
	{
		long long tmpx=lower_bound(nx+1,nx+n+1,x[i])-nx;
		long long tmpy=lower_bound(ny+1,ny+n+1,y[i])-ny;
		return ( (tmpx*x[i]-sumx[tmpx]+sumx[n]-sumx[tmpx]-(n-tmpx)*x[i]) ) + ( tmpy*y[i]-sumy[tmpy]+sumy[n]-sumy[tmpy]-(n-tmpy)*y[i] );
	}
	
	void work()
	{
		scanf("%lld",&n);
		for(long long i=1,a,b;i<=n;i++)
		{
			scanf("%lld%lld",&a,&b);
			x[i]=nx[i]=a+b;
			y[i]=ny[i]=a-b;
		}
		sort(nx+1,nx+n+1);
		sort(ny+1,ny+n+1);
		for(long long i=1;i<=n;i++)
		{
			sumx[i]=sumx[i-1]+nx[i];
			sumy[i]=sumy[i-1]+ny[i];
		}
		
		ans=0x7ffffffffffff;
		for(long long i=1;i<=n;i++)
		{
			ans=min(ans,calc(i));
		}
		printf("%lld",ans>>1);
	}
	
}

int main()
{
	zzc::work();
	return 0;
}

标签:P3964,比雪夫,0.5,gy,gx,long,距离
来源: https://www.cnblogs.com/youth518/p/13650241.html