hdu 5037 Galaxy 鞍山现场赛题目

现场赛卡死的一道题,居然不会维护前缀和,实在是太菜了。

题目大意:  给你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);
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值