bzoj3170 [Tjoi 2013]松鼠聚会

Description

有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1。现在N个松鼠要走到一个松鼠家去,求走过的最短距离。

Input

第一行给出数字N,表示有多少只小松鼠。0<=N<=10^5 下面N行,每行给出x,y表示其家的坐标。 -10^9<=x,y<=10^9

Output

表示为了聚会走的路程和最小为多少。

首先等价变换,旋转坐标系45度,点(x,y)改为((x+y)/2,(x-y)/2),原距离定义改为曼哈顿距离

枚举每个点,分别计算其余点与其x,y坐标差之和

#include<cstdio>
#include<algorithm>
char buf[10000005],*ptr=buf-1;
inline int input(){
    int x=0,c=*++ptr,f=1;
    while(c>57||c<48){if(c=='-')f=-1;c=*++ptr;}
    while(c>47&&c<58)x=x*10+c-48,c=*++ptr;
    return x*f;
}
const int N=100500;
int n;
int x0[N],y0[N],xv[N],yv[N];
long long xs[N],ys[N],ans=1ll<<62;
int main(){
    fread(buf,1,10000000,stdin);
    n=input();
    for(int i=1;i<=n;i++){
        int x=input(),y=input();
        x0[i]=xv[i]=x+y;
        y0[i]=yv[i]=x-y;
    }
    std::sort(xv+1,xv+n+1);
    std::sort(yv+1,yv+n+1);
    for(int i=1;i<=n;i++){
        xs[i]=xs[i-1]+xv[i];
        ys[i]=ys[i-1]+yv[i];
    }
    for(int i=1;i<=n;i++){
        int m=std::lower_bound(xv+1,xv+n+1,x0[i])-xv;
        long long s=(1ll*x0[i]*m-xs[m])+(xs[n]-xs[m]-1ll*x0[i]*(n-m));
        m=std::lower_bound(yv+1,yv+n+1,y0[i])-yv;
        s+=(1ll*y0[i]*m-ys[m])+(ys[n]-ys[m]-1ll*y0[i]*(n-m));
        if(s<ans)ans=s;
    }
    printf("%lld
",ans>>1);
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/5515589.html