这个是2014鞍山现场赛的D。
现场的时候我们两个人都没搞出来,就因为不知道质心怎么求,也就更不知道质心其实是平均数,而那个式子求得是方差。
clj讲完题之后,也是各种郁闷,为啥就看不出来呢。。。。
知道这些之后这题还是挺好出的,初中数学整理一下,就看出怎么预处理了。
用一个数组保存前n项和,一个数组保存前n项平方和。
既然是方差,那最后剩下的数肯定是相邻的。所以O(n)的循环枚举剩下哪一段就好,预处理之后可以O(1)的复杂度可以算出。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=50000+10;
double sum[maxn], a[maxn], seq[maxn];
int n, k;
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &k);
sum[0]=seq[0]=0;
for(int i=1; i<=n; i++)
scanf("%lf", &a[i]);
sort(a+1, a+1+n);
for(int i=1; i<=n; i++)
{
sum[i]=sum[i-1]+a[i];
seq[i]=seq[i-1]+a[i]*a[i];
}
if(k==n)
{
printf("0.0000000000\n");
continue ;
}
double ans=seq[n]-seq[k]-(sum[n]-sum[k])*(sum[n]-sum[k])/(n-k);
int L, R;
for(int i=1; i<=k+1; i++)
{
L=i;
R=L+n-k-1;
ans=min(ans, seq[R]-seq[L-1]-(sum[R]-sum[L-1])*(sum[R]-sum[L-1])/(n-k));
}
printf("%.10lf\n", ans);
}
return 0;
}