BZOJ3170[TJOI2013]松鼠聚会

3170: [Tjoi 2013]松鼠聚会

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 364   Solved: 169
[ 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

Sample Output



20

HINT

Source

乱搞永远是真理~
对于这题,我们可以很容易地得到d(i,j)=max(|xi-xj|,|yi-yj|),
而这个形式是我们所喜闻乐见的
设x'=(x+y)/2,y'=(x-y)/2
那么d(i,j)=|xi'-xj'|+|yi'-yj'|
然后我们就可以分开来统计了
先是统计x轴,将所有松鼠的x'排序
之后我们可以用前缀和和后缀和求出某个松鼠到其他松鼠的X轴距离
具体为 Xi*(i-1)-sum(1..i-1)+sum(i+1..n)-(n-i)*Xi
y轴也同理
乱搞就过了
/**************************************************************
    Problem: 3170
    User: SKYDEC
    Language: C++
    Result: Accepted
    Time:728 ms
    Memory:7840 kb
****************************************************************/
 
#include<stdio.h>
#include<algorithm>
#define BUG printf("yeah!")
#define MAXN 100005
#define Rep(i,j,k) for(long i=j;i<=k;i++)
#define DRep(i,j,k) for(long i=j;i>=k;i--)
using namespace std;
double ans=0;long long n;
struct decar{double x,y;long long num;}a[MAXN];
long long posx[MAXN],posy[MAXN];
double qy[MAXN],dy[MAXN],qx[MAXN],dx[MAXN];
bool cmpx(decar a,decar b){return a.x<b.x;}
bool cmpy(decar a,decar b){return a.y<b.y;}
long long abs(long long x){if(x<0)return -x;else return x;}
int main()
{
    //freopen("meeting.in","r",stdin);freopen("meeting.out","w",stdout);
    scanf("%lld",&n);Rep(i,1,n){scanf("%lf%lf",&a[i].x,&a[i].y);a[i].num=i;double temp=a[i].x;a[i].x=(temp+a[i].y)/2;a[i].y=(temp-a[i].y)/2;}
    sort(a+1,a+1+n,cmpx);qx[1]=a[1].x;Rep(i,2,n)qx[i]=qx[i-1]+a[i].x;dx[1]=a[n].x;DRep(i,n-1,1)dx[n-i+1]=dx[n-i]+a[i].x;
    Rep(i,1,n)posx[a[i].num]=i;
    sort(a+1,a+1+n,cmpy);qy[1]=a[1].y;Rep(i,2,n)qy[i]=qy[i-1]+a[i].y;dy[1]=a[n].y;DRep(i,n-1,1)dy[n-i+1]=dy[n-i]+a[i].y;
    Rep(i,1,n)posy[a[i].num]=i;
    Rep(i,1,n)
    {
        double reux=0;reux=(posx[i]-1)*a[posy[i]].x-qx[posx[i]-1]+dx[n-posx[i]]-(n-posx[i])*a[posy[i]].x;
        double reuy=0;reuy=(posy[i]-1)*a[posy[i]].y-qy[posy[i]-1]+dy[n-posy[i]]-(n-posy[i])*a[posy[i]].y;
        if(reux+reuy<ans||i==1)ans=reux+reuy;
    }
    printf("%.0lf",ans);
    //for(;;);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值