题意:给定n个数轴上的点xi,di是xi到中心mid的距离,可以移动K个到中心mid,求 wi*di^2的和的最小值。
因为wi是1,所以我们可以简化成下面的公式:
I=min(sum(di^2))
=min(sum(xi-mid)^2)
=min(sum(xi^2-2*xi*mid+mid^2)
=min(sum(xi^2) - 2*mid*sum(xi^2) + mid^2) sum下标(0~(n-k))
用前缀和维护xi^2和xi ,时间复杂度是o(n).
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 50005
double x[maxn]; //注意一定是double,如果是int会WA.
int main()
{
// freopen("in.txt", "r", stdin);
int T, k, i, j, n;
double mid, sum1, sum2, ans;
scanf("%d", &T);
while(T--)
{
sum1 = sum2 = 0;
scanf("%d%d", &n, &k);
for(i = 0; i < n; i++) scanf("%lf", &x[i]);
ans = 0;
if(n != k)
{
sort(x, x+n);
for(i = 0; i < n-k; i++)
{
sum1 += x[i]*x[i];
sum2 += x[i];
}
mid = sum2/(n-k);
ans = sum1 - 2*mid*sum2 + mid*mid*(n-k);
for(i = 1, j = n-k; j < n; i++, j++)
{
sum1 -= x[i-1]*x[i-1];
sum1 += x[j]*x[j];
sum2 -= x[i-1];
sum2 += x[j];
mid = sum2/(n-k);
ans = min(ans, (sum1 - 2*mid*sum2 + mid*mid*(n-k)));
}
}
printf("%.10f\n", ans);
}
return 0;
}