题意:给定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 ", ans); } return 0; }