hdu 5073 Galaxy【思维+贪心】

Galaxy

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 4247    Accepted Submission(s): 1028
Special Judge

Problem Description

Good news for us: to release the financial pressure, the government started selling galaxies and we can buy them from now on! The first one who bought a galaxy was Tianming Yun and he gave it to Xin Cheng as a present.


To be fashionable, DRD also bought himself a galaxy. He named it Rho Galaxy. There are n stars in Rho Galaxy, and they have the same weight, namely one unit weight, and a negligible volume. They initially lie in a line rotating around their center of mass.

Everything runs well except one thing. DRD thinks that the galaxy rotates too slow. As we know, to increase the angular speed with the same angular momentum, we have to decrease the moment of inertia.

The moment of inertia I of a set of n stars can be calculated with the formula


where wi is the weight of star i, di is the distance form star i to the mass of center.

As DRD’s friend, ATM, who bought M78 Galaxy, wants to help him. ATM creates some black holes and white holes so that he can transport stars in a negligible time. After transportation, the n stars will also rotate around their new center of mass. Due to financial pressure, ATM can only transport at most k stars. Since volumes of the stars are negligible, two or more stars can be transported to the same position.

Now, you are supposed to calculate the minimum moment of inertia after transportation.

Input

The first line contains an integer T (T ≤ 10), denoting the number of the test cases.

For each test case, the first line contains two integers, n(1 ≤ n ≤ 50000) and k(0 ≤ k ≤ n), as mentioned above. The next line contains n integers representing the positions of the stars. The absolute values of positions will be no more than 50000.

Output

For each test case, output one real number in one line representing the minimum moment of inertia. Your answer will be considered correct if and only if its absolute or relative error is less than 1e-9.

Sample Input

2

3 2

-1 0 1

4 2

-2 -1 1 2

Sample Output

0

0.5

Source

2014 Asia AnShan Regional Contest

 

题目大意:

一共有N个星球,其星球围绕着其中心旋转,现在你可以去掉最多K个星球,使得其最后的:

I=Σ1~ndi*di的值最小,其中di表示第i个点到中心的距离。

当然随着点的去掉,中心一定是不同的。


思路:


1、首先我们考虑K==0的情况,那么其中心就是:center=sum(ai)【1<=i<=n】/n;那么其I=Σ1~n(ai-center)*(ai-center);其中center其实就是n个数的平均数,那么其I其实就是这N个数的方差。


2、那么根据方差的性质:点越少、越密集,值越小,那么其实说最多去掉K个星球就是在打个幌子 ,其实说最多去掉K个星球看起来可能存在去掉去掉1个星球的I值会小于去掉K个星球的I值,其实不然,考虑到方差的性质之后,我们能够确定这样一点:一定是去掉K个星球才能够使得I值最小。


3、那么这样考虑:

①去掉K个点,那么剩下就是N-K个点。

②那么如何让这N-K哥点尽量密集呢?

③我们首先将这N个点排序,(我是从小到大排序的),因为这是一个数轴形式的存在,如图(N=7 K=4):


其我们要留下7-4=3个点,根据点越密集值越小的性质,其实我们分成如下几段求I值,维护最小即可:

(1,2,3)(2,3,4)(3,4,5)(4,5,6)(5,6,7)

当然,如果暴力处理这个解的话时间复杂度是O(n^2),我们要进行一下数学优化。

我们将I=Σ1~n(ai-center)*(ai-center)拆开得到:I=Σai*ai-2*d*Σai+nd*d,(注意这里n是指代剩下的数的个数,在实际计算过程中这里n=n-k);


4、那么我们维护一个ai的前缀和,一个ai*ai的前缀和,然后在枚举的过程中就可以将时间复杂度降到O(n)辣,剩下的过程就是实现代码辣、


5、

①关于输出,因为有spj,直接%lf输出即可。

②关于维护最小值的初始化,值一定要足够大。

③相关计算过程中,注意精度的损失,该long long 的地方就用long long,该用double的地方就要用double。


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
long long int a[500040];
long long int one[500040];
long long int two[500040];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        memset(one,0,sizeof(one));
        memset(two,0,sizeof(two));
        for(int i=1;i<=n;i++)
        {
           scanf("%I64d",&a[i]);
        }
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++)
        {
           if(i==1)one[i]=a[i];
           else
           one[i]=one[i-1]+a[i];
           if(i==1)two[i]=a[i]*a[i];
           else
           two[i]=two[i-1]+a[i]*a[i];
        }
        double ans=1000000000000000000;
        long long int sum=0;
        for(int i=1;i<=n;i++)
        {
            if(i>=n-k)
            {
                sum=one[i]-one[i-(n-k)];
                double d=sum*1.0/(n-k)*1.0;
                double tmp=two[i]-two[i-(n-k)]-2*d*sum+(n-k)*d*d;
                ans=min(ans,tmp);
            }
        }
        if(n==k)ans=0;
        printf("%.10lf\n",ans);
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值