[BZOJ3170][Tjoi2013]松鼠聚会(平面几何)

传送门


首先我们发现,在这题中上下左右斜八个方向的距离被定义为相等的,那么大概就是这样:
这里写图片描述
那么两点之间的距离实际上是一个切比雪夫距离。
切比雪夫距离表示如下:

dis=max(|x1x2|,|y1y2|) d i s = m a x ( | x 1 − x 2 | , | y 1 − y 2 | )

因为坐标的范围敲大,所以我们并不能直接使用切比雪夫距离。
那么我们有一个距离计算方式可以解决这个问题,那么就是曼哈顿距离:
dis=|x1x2|+|y1y2| d i s = | x 1 − x 2 | + | y 1 − y 2 |

为什么呢?因为他的横纵坐标是分开的,那么我们可以通过前缀和和后缀和来计算出距离和。
首先计算横坐标,先按横坐标排序,对于在i个点首先继承前缀和,然后前面i-1个点的距离都要加上(a[i].x-a[i-1].x),然后计算后面的点到他的距离和,所以要在做一遍后缀和,纵坐标同理。

那么我们要如何转化他们呢?首先看一下曼哈顿距离转化为切比雪夫距离:
dis=|x1x2|+|y1y2| d i s = | x 1 − x 2 | + | y 1 − y 2 |
|x1x2|=max(x1x2,x2x1) ∵ | x 1 − x 2 | = m a x ( x 1 − x 2 , x 2 − x 1 )
dis=max(x1x2+y1y2,x2x1+y1y2,x1x2+y2y1,x2x1+y2y1) ∴ d i s = m a x ( x 1 − x 2 + y 1 − y 2 , x 2 − x 1 + y 1 − y 2 , x 1 − x 2 + y 2 − y 1 , x 2 − x 1 + y 2 − y 1 )
=max((x1+y1)(x2+y2),(x1y1)+(x2y2),(x1y1)(x2y2),(x1+y1)+(x2+y2)) = m a x ( ( x 1 + y 1 ) − ( x 2 + y 2 ) , − ( x 1 − y 1 ) + ( x 2 − y 2 ) , ( x 1 − y 1 ) − ( x 2 − y 2 ) , − ( x 1 + y 1 ) + ( x 2 + y 2 ) )
X=x+y,Y=xy 设 X = x + y , Y = x − y
dis=max(X1X2,Y2Y1,Y1Y2,X2X1) 则 d i s = m a x ( X 1 − X 2 , Y 2 − Y 1 , Y 1 − Y 2 , X 2 − X 1 )
=max(|X1X2|,|Y1Y2|) = m a x ( | X 1 − X 2 | , | Y 1 − Y 2 | )
看吧,这样就转换成了切比雪夫距离。
那么我们如何吧切比雪夫距离转换成曼哈顿距离呢?只要把上面的运算倒过来
dis=max(|x1x2|,|y1y2|) d i s = m a x ( | x 1 − x 2 | , | y 1 − y 2 | )
=max(x1x2,x2x1,y1y2,y2y1) = m a x ( x 1 − x 2 , x 2 − x 1 , y 1 − y 2 , y 2 − y 1 ) · · · · ①
X=x+y,Y=xy 设 X = x + y , Y = x − y
X1=x1+y1,Y1=x1y1,X2=x2+y2,Y3=x2y2 则 X 1 = x 1 + y 1 , Y 1 = x 1 − y 1 , X 2 = x 2 + y 2 , Y 3 = x 2 − y 2
x1=X1+Y12,y1=X1Y12 x 1 = X 1 + Y 1 2 , y 1 = X 1 − Y 1 2
x2=X2+Y22,y2=X2Y22 x 2 = X 2 + Y 2 2 , y 2 = X 2 − Y 2 2
带入①式得
dis=max(X1X2+Y1Y22,X2X1+Y1Y22,X1X2+Y2Y12,X2X1+Y2Y12) d i s = m a x ( X 1 − X 2 + Y 1 − Y 2 2 , X 2 − X 1 + Y 1 − Y 2 2 , X 1 − X 2 + Y 2 − Y 1 2 , X 2 − X 1 + Y 2 − Y 1 2 )
2dis=max(X1X2+Y1Y2,X2X1+Y1Y2,X1X2+Y2Y1,X2X1+Y2Y1) ∴ 2 ∗ d i s = m a x ( X 1 − X 2 + Y 1 − Y 2 , X 2 − X 1 + Y 1 − Y 2 , X 1 − X 2 + Y 2 − Y 1 , X 2 − X 1 + Y 2 − Y 1 )
|x1x2|=max(x1x2,x2x1) 又 ∵ | x 1 − x 2 | = m a x ( x 1 − x 2 , x 2 − x 1 )
2dis=|X1X2|+|Y1Y2| 所 以 2 ∗ d i s = | X 1 − X 2 | + | Y 1 − Y 2 |
dis=|X1X2|+|Y1Y2|2 即 d i s = | X 1 − X 2 | + | Y 1 − Y 2 | 2

因为精度问题所以我们先按2*dis来搞,最后ans/2。


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=100010;
inline ll read()
{
    ll x=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct point
{ 
    ll x,y;
    int id;
}a[N]; ll w[N]; 
bool cmp1(point a,point b){return a.x<b.x;}
bool cmp2(point a,point b){return a.y<b.y;}
ll s[N],d[N];//前缀和,后缀和
int main()
{
    int n; scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        ll x=read(),y=read();
        a[i].x=(x+y),a[i].y=(x-y);
        a[i].id=i;
    }
    sort(a+1,a+n+1,cmp1);
    s[0]=0;   for(int i=1;i<=n;i++) s[i]=s[i-1]+(a[i].x-a[i-1].x)*(i-1);
    d[n+1]=0; for(int i=n;i>=1;i--) d[i]=d[i+1]+(a[i+1].x-a[i].x)*(n-i);
    for(int i=1;i<=n;i++) w[a[i].id]+=s[i]+d[i]; 

    sort(a+1,a+n+1,cmp2);
    s[0]=0;   for(int i=1;i<=n;i++) s[i]=s[i-1]+(a[i].y-a[i-1].y)*(i-1);
    d[n+1]=0; for(int i=n;i>=1;i--) d[i]=d[i+1]+(a[i+1].y-a[i].y)*(n-i);
    for(int i=1;i<=n;i++) w[a[i].id]+=s[i]+d[i]; 

    ll maxx=1LL<<63-1;
    for(int i=1;i<=n;i++) maxx=min(maxx,w[i]);
    printf("%lld\n",maxx>>1);

    return 0; 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值