您的位置:首页 > 其它

hdu 5037 Galaxy 鞍山现场赛题目

2014-10-24 08:46 253 查看
现场赛卡死的一道题,居然不会维护前缀和,实在是太菜了。

题目大意: 给你N个星球,你可以拿走K个星球放到任意的位置上去,星球都在x轴上,星球的质量都为1,求各个星球到质心的方差最小值。

证明1:拿走K个星球,剩下N-K个星球,将K个星球放到剩余星系的质心上方差最小。

定理:对v个星球,他们的质心为方差最小的位置,如果发生改变方差会变大.

ave = (x1+.....+xv)/v;假设不在质心上,那么假设放在ave+y(y可正可负).

sum (xi-ave-y)^2 = sum(xi-ave)^2//放在质心的方差

+sum(y^2)//一定大于0

+sum(2*(xi-ave)y)// sum(xi-ave) = sum(xi)-ave*v = 0

得证

证明2:一定是从两端拿走星球使得方差最小,那么拿走剩下的一定是连续的

对于三个点x1 < x2 < x3.他们的质心一定在x1 和 x3 之间,如果我拿走x2,假设质心在x2 与 x3 之间的情况,那么一定拿走x1会使得方差更小。反之如果在x1 x2之间的话,同理拿走x3更小,所以一定是拿走两端的点使得方差最小。

错证:从两端拿走拿走到当前质心最远的点。当时比赛就是这么做的,当时没能证明出来,事实上是错的,这种策略局部最优不表示整体最优,错误数据如

input

1

5 3

1 2 3 100 100

output

0

然后比赛就跪了

所以只需要在前两个贪心的基础上,维护两个前缀和就可以解决了.

#include<iostream>

#include<cstdio>

#include<algorithm>

using namespace std;

double a[50005];

double sum,s;

bool cmp (double a,double b){

return a < b;

}

int main(){

int T;

scanf("%d",&T);

while(T--){

int num,K;

sum = 0;s = 0;

scanf("%d%d",&num,&K);

int N = num - K;

double ans = 0;

for(int i=0;i<num;i++){

scanf("%lf",&a[i]);

}

sort(a,a+num,cmp);

if(K+1>=num)printf("%.10f\n",0.0);

else{

for(int i=0;i<N;i++){

sum+=a[i];

s+=a[i]*a[i];

}

ans = s-double(sum*sum/N);

for(int i=N;i<num;i++){

s = s - a[i-N]*a[i-N]+a[i]*a[i];

sum = sum - a[i-N] + a[i];

double tem = s-double(sum*sum/N);

ans = min(ans,tem);

}

printf("%.10f\n",ans);

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: