1. 程式人生 > 其它 >洛谷P3964 [TJOI2013]松鼠聚會

洛谷P3964 [TJOI2013]松鼠聚會

這個小辣雞怎麼連切比雪夫距離都不會啊。。。

題目

https://www.luogu.com.cn/problem/P3964

思路

切比雪夫距離

定義

\((x1,y1)\)\((x2,y2)\)的切比雪夫距離為: \(dis=max(\lvert x1-x2\rvert,\lvert y1-y2\rvert)\)

切比雪夫距離與曼哈頓距離的變換

顯然這個東西既包含絕對值又包含最值,非常不好處理。

但是我們有一種轉化方法珂以將切比雪夫距離轉化成曼哈頓距離。當然逆變換也必然是存在的。我這裡推一遍曼哈頓距離到切比雪夫距離的變換。

假設兩個點為\((x1,y1)\)\((x2,y2)\),那麼它們的曼哈頓距離為:\(\lvert x1-x2\rvert + \lvert y1-y2\rvert\)

,考慮把絕對值拆掉:

\(\lvert x1-x2\rvert + \lvert y1-y2\rvert\)=\(max(x1-x2+y1-y2 , x1-x2+y2-y1 , x2-x1+y1-y2 , x2-x1+y2-y1)\)

現在發現式子已經變成了一個max的形式。注意到\(x1-x2+y1-y2=-(x2-x1+y2-y1)\),把式子中互為相反數的部分並在一起,得:

\(max(max(x1-x2+y1-y2,x2-x1+y2-y1),max(x1-x2+y2-y1,x2-x1+y1-y2))\)

就是\(max(\lvert x1-x2+y1-y2\rvert,\lvert x1-x2-(y1-y2)\rvert)\)

=\(max(\lvert x1+y1-(x2+y2)\rvert,\lvert x1-y1-(x2-y2)\rvert)\)

對照切比雪夫距離的定義,我們令 \(x1'=x1+y1\) , \(y1'=x1-y1\) , \(x2'=x2+y2\) , \(y2'=x2-y2\)

則距離可寫為 \(max(\vert x1'-x2'\rvert,\lvert y1'-y2'\rvert)\)

所以曼哈頓意義下的\((x,y)\),對應於切比雪夫意義下的\((x+y,x-y)\)

同樣,我們珂以很容易地做一個逆變換,把切比雪夫意義下的\((x,y)\)對映到曼哈頓意義下的\((\frac{x+y}{2},\frac{x-y}{2})\)

(這堆式子用了markdown還是好醜啊,其實自己在草稿上推一遍挺快的qwq)

解題

現在問題變成了,給出一堆點,求其中的一個點,使所有點到該點的曼哈頓距離之和最小。

列舉每一個點,計算集合點在該點的代價。那就是很經典的珂以用字首和維護的問題了。

程式碼


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ll long long
#define maxn (int)(1e5+10)
using namespace std;
struct point{
    ll x,y;
} p[maxn];
bool cmp1(point p1,point p2){
    return p1.x<p2.x;
}
bool cmp2(point p1,point p2){
    return p1.y<p2.y;
}
ll X[maxn],Y[maxn];
ll pre_x[maxn],pre_y[maxn];
int n;
ll cal(int id){
    ll sum=0;
    int i;
    i=lower_bound(X+1,X+n+1,p[id].x)-X;
    sum+=(p[id].x*(i-1)-pre_x[i-1])+(pre_x[n]-pre_x[i-1]-p[id].x*(n-i+1));
    i=lower_bound(Y+1,Y+n+1,p[id].y)-Y;
    sum+=(p[id].y*(i-1)-pre_y[i-1])+(pre_y[n]-pre_y[i-1]-p[id].y*(n-i+1));
    return sum;
}
int main(){
    int i;
    ll tx,ty;
    ll ans=-1;
    scanf("%d",&n);
    for(i=1;i<=n;++i){
        scanf("%lld%lld",&tx,&ty);
        p[i].x=tx+ty;p[i].y=tx-ty;
    }
    sort(p+1,p+n+1,cmp2);
    for(i=1;i<=n;++i){
        Y[i]=p[i].y;
        pre_y[i]=pre_y[i-1]+Y[i];
    }
    sort(p+1,p+n+1,cmp1);
    for(i=1;i<=n;++i){
        X[i]=p[i].x;
        pre_x[i]=pre_x[i-1]+X[i];
    }
    for(i=1;i<=n;++i){
        ans=ans<0?cal(i):min(ans,cal(i));
    }
    printf("%lld",ans/2);
    // system("pause");
    return 0;
}