[TJOI2013]松鼠聚會(枚舉)
[TJOI2013]松鼠聚會
題目描述
草原上住著一群小松鼠,每個小松鼠都有一個家。時間長了,大家覺得應該聚一聚。但是草原非常大,松鼠們都很頭疼應該在誰家聚會才最合理。
每個小松鼠的家可以用一個點x,y表示,兩個點的距離定義為點(x,y)和它周圍的8個點(x-1,y)(x+1,y),(x,y-1),(x,y+1).(x-1,y+1),(x-1,y-1),(x+1,y+1),(x+1,y-1)距離為1。
輸入輸出格式
輸入格式:
第一行是一個整數N,表示有多少只松鼠。接下來N行,第i行是兩個整數x和y,表示松鼠i的家的坐標
輸出格式:
一個整數,表示松鼠為了聚會走的路程和最小是多少。
輸入輸出樣例
輸入樣例#1:
6
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2
輸出樣例#1:
20
輸入樣例#2:
6
0 0
2 0
-5 -2
2 -2
-1 2
4 0
輸出樣例#2:
15
說明
樣例解釋
在第一個樣例中,松鼠在第二只松鼠家(-1,-2)聚會;在第二個樣例中,松鼠在第一只松鼠家(0.0)聚會。
數據範圍
30%的數據,0 ≤ N ≤ 1000
100%的數據,0 ≤ N ≤ 100000; ?10^9 ≤ x, y ≤ 10^9
第一次聽說切比雪夫距離這個東西,它可以這樣與曼哈頓距離轉換。
將一個點 (x,y) 的坐標變為 \((x+y,x?y)\) 後,原坐標系中的曼哈頓距離 = 新坐標系中的切比雪夫距離
將一個點 (x,y) 的坐標變為 \((\frac{x+y}{2},\frac{x-y}{2})\)
於是我們把原坐標系轉化一下,轉成更加熟悉的曼哈頓距離。
考慮枚舉在哪只松鼠家聚會,聚會的路程為\(\sum|X_i-X|+|Y_i-Y|\),但是這樣絕對值很難處理。我們可以把X[],Y[]排序,然後查找一下X,Y位置,通過前綴和處理一下就能快速算答案了。
為什麽最小的點答案都會超過1<<40???
然後順序加會long long,換一下加減法順序就過了???
#include<bits/stdc++.h> #define lll long long using namespace std; lll read(){ lll x=0,w=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*w; } const lll N=100010; lll n,p,q,sx,sy,ans=(1ll<<62); lll x[N],y[N],xx[N],yy[N],sumx[N],sumy[N]; lll check1(lll v){ lll l=1,r=n; while(l<r){ lll mid=(l+r)/2; if(x[mid]>=v)r=mid; else l=mid+1; }return l; } lll check2(lll v){ lll l=1,r=n; while(l<r){ lll mid=(l+r)/2; if(y[mid]>=v)r=mid; else l=mid+1; }return l; } int main(){ n=read(); for(lll i=1;i<=n;i++){ p=read();q=read(); xx[i]=x[i]=p+q;yy[i]=y[i]=p-q; } sort(x+1,x+1+n);sort(y+1,y+1+n); for(lll i=1;i<=n;i++) sumx[i]=sumx[i-1]+x[i],sumy[i]=sumy[i-1]+y[i]; for(lll i=1;i<=n;i++){ lll p1=check1(xx[i]),p2=check2(yy[i]); sx=sumx[n]-sumx[p1]-(n-p1)*xx[i]+p1*xx[i]-sumx[p1]; sy=sumy[n]-sumy[p2]-(n-p2)*yy[i]+p2*yy[i]-sumy[p2]; ans=min(ans,sx+sy); }printf("%lld\n",ans/2); }
[TJOI2013]松鼠聚會(枚舉)