【CJOJ P2110】YL杯超级篮球赛
【CJOJ P2110】YL杯超级篮球赛
Description
一年一度的高一YL杯超级篮球赛开赛了。当然,所谓超级的意思是参赛人数可能多于5人。小三对这场篮球赛非常感兴趣,所以一场都没有落下。每天中午都准时守候在篮球场看比赛。经过一个星期的研究,小三终于对篮球的技战术找到了一丝丝感觉。他发现打YL杯的每个班都有一套相似的进攻战术:
1.控球后卫带球到前场,找到一个最佳攻击点(x,y)。
2.所有除控卫以外的队员都从各自的当前位置迅速向(x,y)移动。
3.控球后卫根据场上情况组织进攻。
这个战术对于一般情况是非常奏效的,但是每个队员毕竟不像小三一样每天精力过剩,每个队员都有一个疲劳指数w,显然对于每个队员的移动需要消耗一些能量。
假设一个队员从位置xl,y1)移动到(x,y)的能量消耗为w*(ABS(x-x1)+ABS(y-y1)),这里ABS为绝对值函数,那么我们希望整个队伍一次进攻的能量消耗当然是越少越好。显然能量消耗的多少直接取决于控球后卫对于攻击点(x,y)的选择。
因为参赛人数众多,所以小三希望你能编写一个程序,帮他找出某个时刻的最佳攻击点。
Input
第一行:一个整数N,表示篮球队人数
第二行:一共N个整数,其中的第i个数Wi表示第i个队员的疲劳指数。
第3~N+2行:每一行两个整数x和Y,表示其中的第i+2行,表示第i个队员的当前位置的横坐标和纵坐标。
Output
一个实数。表示所有队员集合到最佳攻击位置的能量消耗总和,答案保留两位小数。
样例输入
1
1
0 0
样例输出
0.00
数据规模
n<=50000
0<w<=1000
0<x,y<=1000000
题解
这道题有点像士兵站队问题,每一个人的疲劳值直接看成重复的几个人即可。可以自己试着画一下,发现会很简单。把每个人的横坐标、纵坐标全部排序,然后依次就中位数计算就可以了,具体的证明请自己温习初一的绝对值距离。这道题的写法很好的利用到了中位数/绝对值的使用。
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int w[50001],n;
long long sum=0;
struct dsl
{
int a;
int w;
};//结构体定义
bool cmp(dsl k,dsl d)
{
return k.a<d.a;
}//比较函数(方便直接调用sort)
dsl x[50001],y[50001];
int main()
{
//读入
long long cd=0;
cin>>n;
for(int i=1;i<=n;++i)
{
scanf("%d",&w[i]);
x[i].w=w[i];
y[i].w=w[i];
cd+=w[i];
}
for(int i=1;i<=n;++i)
scanf("%d%d",&x[i].a,&y[i].a);
//排序
sort(&x[1],&x[n+1],cmp);
sort(&y[1],&y[n+1],cmp);
//计算
int k;
cd=int(((cd+1)/2)+0.5);
long long g=cd;
for(int i=1;i<=n;++i)
{
cd-=x[i].w;
if(cd<=0){k=i;break;}
}
for(int i=1;i<=n;++i)
sum+=abs(x[k].a-x[i].a)*x[i].w;
cd=g;
for(int i=1;i<=n;++i)
{
cd-=y[i].w;
if(cd<=0){k=i;break;}
}
for(int i=1;i<=n;++i)
sum+=abs(y[k].a-y[i].a)*y[i].w;
//利用绝对值进行计算
//输出
cout<<sum<<".00"<<endl;
//由绝对值的最小值和题目数据可知,结果一定是一个整数
//但是要求输出的事小数点后两位,所以直接打印".00"
return 0;
}