hdu 5073穴+分散貪欲

1834 ワード

http://acm.hdu.edu.cn/showproblem.php?pid=5073
あなたにn個の数をあげて、n個の星の位置を代表して、すべての星の重量はすべて1の初めの時すべての星はすべて質心の周りを回転して、それでは質心の位置はすべての星の位置の和/星の個数は今あなたにk個の星を任意の位置に移動させます(複数の星は同じ位置で、すべての星は同じ直線の上で)移動後、それらのコアの位置が変化する可能性があります.I=sum(di^2)(diはi番目の星がコアに到達する距離を表します)を最小にします.
分散の性質(密であればあるほど小さい)から貪欲な策略は、n-k配列が必ず連続していることを知って、それではすぐに連続するn-k配列の中で分散が最も小さいものを求めます
連続長をkとする
avg = sum/k;
和を求める(pi-avg)^2=(和を求めるpi^2)  -  sum^2/k;
シミュレーションをしてみましょう
入力シーケンス式無秩序、サンプルピット死、sortまたはsum^2/k精度問題WA死
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <iostream>
#include <algorithm>
using namespace std;
#define RD(x) scanf("%I64d",&x)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define clr0(x) memset(x,0,sizeof(x))
typedef long long LL;
const int maxn = 5e4+5;
const double INF = 1e20;
int n,k;
LL p[maxn],sum[maxn],sq[maxn];
int main() {
    int _;RD(_);while(_--){
        RD2(n,k);
        p[0] = sum[0] = sq[0] = 0;
        for(int i = 1;i <= n;++i)
            RD(p[i]);
        double ans = INF;
        k = n - k;
        if(k == 0 || k == 1){
            puts("0");
            continue;
        }
        sort(p+1,p+n+1);
        for(int i = 1;i <= n;++i)
            sum[i] = p[i] + sum[i-1],sq[i] = p[i]*p[i] + sq[i-1];
        for(int i = k;i <= n;++i)
            ans = min(ans,(double)(sq[i] - sq[i - k])*(double)k - (double)(sum[i] - sum[i-k])*(double)(sum[i] - sum[i-k]));
        printf("%.10lf
",ans/(double)k); } return 0; }