您的位置:首页 > 其它

hdu5073Galaxy dp

2015-10-12 21:35 211 查看
//n个数,最多移动k个数,使得这
//n个数的segment((xi - X)^2)(1<=i<=n)
//其中X为这n个数的平均数
//可以考虑将k个数移动到剩下的(n-k)个数的
//平均数中,然后就相当于,从n中选k个数其方差最小
//然后可以将这n个数排一下序,选的n-k的数一定是
//连续的,这个应该比较容易想到,然后
//dp[i] 表示最后一个数为i的连续n-k个数方差
//然后记录一下sum(这n-k个数的和)就能更新
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std ;
const int maxn = 1e5+10 ;
double a[maxn] ;
double dp[maxn] ;
int main()
{
int t ;
scanf("%d" , &t) ;
while(t--)
{
int n  , k ;
scanf("%d%d" , &n , &k) ;
for(int  i = 1;i <= n;i++)
scanf("%lf" , &a[i]) ;
sort(a+1 , a+1+n) ;
if(k == n)
{
puts("0") ;
continue ;
}
memset(dp , 0 , sizeof(dp)) ;
double sum = 0 ;
for(int i = 1;i <= n-k;i++)
sum += a[i] ;
for(int i = 1;i <= n-k;i++)
dp[n-k] += (a[i]*(n-k)-sum)*((n-k)*a[i]-sum) ;
double ans = dp[n-k] ;
for(int i = n-k;i < n;i++)
{
int j = i-(n-k) + 1 ;
double tmp1 =  pow(((n-k)*a[j]-sum)*1.0 , 2) ;
double tmp2 =  2*((a[j]-a[i+1])*(n-k)*(sum-a[j])) ;
double tmp3 = (n-k-1)*pow((a[j]-a[i+1])*1.0,2) ;
double tmp4 = pow(((n-k)*a[i+1]-(sum-a[j]+a[i+1]))*1.0 , 2) ;
dp[i+1] = dp[i] - tmp1 + tmp2 +tmp3 + tmp4;
double tmp = 2*(a[j] - a[i+1])*sum*(n-k-1) ;
dp[i+1] -= tmp ;
ans = min(ans , dp[i+1]) ;
sum = sum - a[j] + a[i+1] ;
}
printf("%.9lf\n" , ans/((n-k)*(n-k)*1.0)) ;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: