HDU 5073 思维

HDU 5073
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5073
题意:
给出n行星的位置,每个行星质量为1.
最多可以移动m个行星。问移动后他们到他们质心距离平方的和最小是多少。
思路:
移动可以看成删除。
容易知道最后剩下的n-m个行星在原来的数轴中连续为最佳,故问题简化为怎么求一段含有n-m个行星的区间内行星到质心距离平方的和的最小值。
因为距离和=sigma((x-d)*(x-d)),d为质心坐标,x为行星坐标,所以可以用前缀和的方式处理。
源码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <iostream>
using namespace std;
#define inf (1000000000000)
const int MAXN = 50000 + 5;
double pos[MAXN];
double sum[MAXN], two[MAXN];
bool cmp(int a, int b){return a < b;}
int main()
{
//    freopen("D.in", "r", stdin);
    int t;
    scanf("%d", &t);
    while(t--){
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 1 ; i <= n ; i++)
            scanf("%lf", &pos[i]);
        if(n == m || n == m + 1){
            printf("0\n");
            continue;
        }
        sort(pos + 1, pos + n + 1, cmp);
        sum[0] = two[0] = 0;
        for(int i = 1 ; i <= n ; i++){
//            printf("pos[%d] = %f\n", i, pos[i]);
            sum[i] = sum[i - 1] + pos[i];
            two[i] = two[i - 1] + pos[i] * pos[i];
//            printf("sum[%d] = %f, two[%d] = %f\n", i, sum[i], i, two[i]);
        }
        double d1 = sum[n - m] / (n - m);
        double ans = two[n - m] - 2 * sum[n - m] * d1 + d1 * d1 * (n - m);
//        printf("d1 = %f\n", d1);
//        printf("ans = %f\n", ans);
        double d2;
        double pre = ans;
        for(int i = n - m + 1; i <= n ; i++){
            double d2 = (sum[i] - sum[i - n + m]) / (n - m);
            double tans = two[i] - two[i - n + m] - 2 * (sum[i] - sum[i - n + m]) * d2 + d2 * d2 * (n - m);
//            printf("d2 = %f\n", d2);
//            printf("first = %f, second = %f\n", two[i] - two[i - n + m], sum[i] - sum[i - n + m]);
//            printf("i = %d, tans = %f\n", i, tans);
            ans = min(ans, tans);
        }
        printf("%.10f\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值