3170: [Tjoi 2013]松鼠聚会
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 531 Solved: 249
[Submit][Status]
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
表示为了聚会走的路程和最小为多少。
Sample Input
6
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2
Sample Output
20
HINT
Source
题解:
我们有两个式子:max(a,b)=(a+b)/2 +|(a-b)/2|
以及:max(|a|,|b|)=|(a+b)/2|+|(a-b)/2|
然后对这题来说dist(i,j)=max(|xi-xj|,|yi-yj|),然后=|(xi-xj+yi-yj)/2|+|(xi-xj-yi+yj)|
我们另x‘=x+y,y’=x-y,则2*dist(i,j)=|xi‘-xj’|+|yi‘-yj’|
然后就可以前缀和后缀和扫一遍得出答案了。
代码:
#include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> #include<vector> #include<map> #include<set> #include<queue> #include<string> #define inf 1000000000000000ll #define maxn 100000+5 #define maxm 500+100 #define eps 1e-10 #define ll long long #define pa pair<int,int> #define for0(i,n) for(int i=0;i<=(n);i++) #define for1(i,n) for(int i=1;i<=(n);i++) #define for2(i,x,y) for(int i=(x);i<=(y);i++) #define for3(i,x,y) for(int i=(x);i>=(y);i--) #define mod 1000000007 using namespace std; inline int read() { int x=,f=;char ch=getchar(); while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();} while(ch>=''&&ch<=''){x=*x+ch-'';ch=getchar();} return x*f; }
struct rec{int x,y;ll z;}a[maxn];
int n;
inline bool cmp1(rec a,rec b){return a.x<b.x;}
inline bool cmp2(rec a,rec b){return a.y<b.y;} int main() { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); n=read();
for1(i,n)
{
int x=read(),y=read();
a[i].x=x+y;a[i].y=x-y;
}
sort(a+,a+n+,cmp1);
ll sum=;
for1(i,n)
{
a[i].z+=(ll)a[i].x*(ll)(i-)-sum;
sum+=(ll)a[i].x;
}
sum=;
for3(i,n,)
{
a[i].z+=sum-(ll)a[i].x*(ll)(n-i);
sum+=(ll)a[i].x;
}
sort(a+,a+n+,cmp2);
sum=;
for1(i,n)
{
a[i].z+=(ll)a[i].y*(ll)(i-)-sum;
sum+=(ll)a[i].y;
}
sum=;
for3(i,n,)
{
a[i].z+=sum-(ll)a[i].y*(ll)(n-i);
sum+=(ll)a[i].y;
}
ll ans=inf;
for1(i,n)ans=min(ans,a[i].z);
printf("%lld\n",ans>>); return ; }