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;
}