1. 程式人生 > >BZOJ_3170_[Tjoi2013]松鼠聚會_切比雪夫距離+前綴和

BZOJ_3170_[Tjoi2013]松鼠聚會_切比雪夫距離+前綴和

zoj 左右 struct Language number 上下左右 truct include ans

BZOJ_3170_[Tjoi2013]松鼠聚會_切比雪夫距離+前綴和

題意:有N個小松鼠,它們的家用一個點x,y表示,兩個點的距離定義為:點(x,y)和它周圍的8個點即上下左右四個點和對角的四個點,距離為1。現在N個松鼠要走到一個松鼠家去,求走過的最短距離。

分析:

這啥奇怪的距離表示啊。推了一下發現是max{ abs(x[i] - x[j]),abs(y[i] - y[j] }。然後就不會了。

看題姐:這個東西叫切比雪夫距離,可以和曼哈頓距離轉化。

把坐標變成(x[i]-y[i])/2,(x[i]+y[i])/2,求一遍曼哈頓距離,展開再分類討論一下發現和上面那個式子是等價的。

太強了太強了。

曼哈頓距離就好辦了。可以對x軸y軸分別求前綴和。

快速求出任意一點到其他所有點的距離:x[i]*(i-1)-s[i-1]+s[n]-s[i]-(n-i)*x[i](s為前綴和。)

代碼:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 100050
#define LL long long
struct A{
    int id,x,y;
}a[N];
int n;
LL xx[N],yy[N],ans,s[N];
bool cmp1(const A &g,const A &h){
    return g.x<h.x;
}
bool cmp2(const A &g,const A &h){
    return g.y<h.y;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        a[i].id=i;
        scanf("%d%d",&a[i].x,&a[i].y);
        int tmp=a[i].x;
        a[i].x=a[i].x+a[i].y;
        a[i].y=tmp-a[i].y;
    }
    sort(a+1,a+n+1,cmp1);
    for(int i=1;i<=n;i++){
        s[i]=s[i-1]+a[i].x;
    }
    for(int i=1;i<=n;i++){
        xx[a[i].id]=1ll*a[i].x*(i-1)-s[i-1]+s[n]-s[i]-1ll*(n-i)*a[i].x;
    }
    sort(a+1,a+n+1,cmp2);
    for(int i=1;i<=n;i++){
        s[i]=s[i-1]+a[i].y;
    }
    LL ans=1ll<<60;
    for(int i=1;i<=n;i++){
        yy[a[i].id]=1ll*a[i].y*(i-1)-s[i-1]+s[n]-s[i]-1ll*(n-i)*a[i].y;
        ans=min(ans,xx[a[i].id]+yy[a[i].id]);
    }
    printf("%lld\n",ans>>1);
}	

BZOJ_3170_[Tjoi2013]松鼠聚會_切比雪夫距離+前綴和