CodeForce 626E Simple Skewness (貪心+三分)

題目:給出n個數字,求出一個子集,使得其平均數與中位數的差值最大。

解析:首先將a[1...n]從大到小排序,在固定中位數的位置後,子集的構成必然是在中位數位置的兩側選取相同個,顯然,每側要儘量選取較大的值。

可以發現,選取的個數與平均數具有凸函數性質,所以通過三分找到臨界點。整體複雜度O(nlogn)。

[code]:

#include<bits/stdc++.h>

using namespace std;

const int maxn = 2e5+5;

int n,a[maxn];
int o1,o2;
double ans,s[maxn];

void init(){
    ans = -1e9;
}

double f(int p,int x,int a,int b){
    return (s[x-1]+s[p+x]-s[p]+b)/(2*x+a);
}

void sol(){
    double median;
    int i,j,p1,p2;
    int mid1,mid2,l,r,t1,t2;
    for(i = 0;i < 2*n-1;i++){
        if(i&1) p1=i/2,p2=p1+1,t1=2,t2=a[p1]+a[p2],median=1.0*t2/2.0;
        else p1=p2=i/2,t1=1,t2=a[p1],median=a[p1];
        l = 0,r = min(p1,n-p2);
        while(r-l>2){
            mid1 = l+(r-l)/3;
            mid2 = l+2*(r-l)/3;
            if(f(p2,mid1,t1,t2)>=f(p2,mid2,t1,t2)) r = mid2;
            else l = mid1;
        }
        for(j = l;j <= r;j++){
            if(ans < f(p2,j,t1,t2)-median){
                o1 = i,o2 = j;
                ans = f(p2,j,t1,t2)-median;
            }
        }
    }
    printf("%d\n",2*o2+1+(o1&1));
    for(i = 0;i < o2;i++) printf("%d ",a[i]);
    printf("%d ",a[i=o1/2]);
    if(o1&1) printf("%d ",a[i=o1/2+1]);
    for(j = 0;j < o2;j++) printf("%d ",a[++i]);
}

int main(){
    int i,j;
    scanf("%d",&n);
    for(i = 0;i < n;i++) scanf("%d",&a[i]);
    sort(a,a+n);
    reverse(a,a+n);
    s[0] = a[0];
    for(i = 1;i < n;i++) s[i] = s[i-1]+a[i];
    sol();

    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章