题目链接:https://gmoj.net/senior/#main/show/1325
分析
带权中位数模板题。
带权中位数,就是给定的N个数都有一个权值,或者说相当于个数。此时的中位数就不再是第N/2个数了,而是第 ∑ d i / n \sum{d_i}/n ∑di/n个数。
有这样一类题,给出了若干个排列在一条直线上的点,每个点有一个权值,比如说货物量、人数什么的,然后让我们找出使所有点的货物、人集合到一个点的总代价最小的位置。我们将会发现,这一类问题实际上就是带权中位数问题。
这题就是分别求横纵坐标的带权中位数。再利用公式算出代价。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
ll n,s,ans,t,px,py;
struct node
{
int w,x,y;
}a[50005];
int cmp1(node l,node r) {return l.x<r.x;}
int cmp2(node l,node r) {return l.y<r.y;}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].w);
s+=a[i].w;
}
ll mid=s/2;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
sort(a+1,a+n+1,cmp1);
for(int i=1;i<=n;i++)
{
t+=a[i].w;
if(t>=mid)
{
px=a[i].x;
break;
}
}
sort(a+1,a+n+1,cmp2);
t=0;
for(int i=1;i<=n;i++)
{
t+=a[i].w;
if(t>=mid)
{
py=a[i].y;
break;
}
}
ans=0;
for(int i=1;i<=n;i++)
{
ans+=a[i].w*(abs(a[i].x-px)+abs(a[i].y-py));
}
cout<<ans<<".00";
return 0;
}