Codeforces 626 E Simple Skewness —— 二分

This way

题意:

给你一些数,让你找出几个数,使得这些数的平均数-中位数最大,问你这些数是哪些。

题解:

奇数:

奇数的话,中位数便非常好确定了,那么我们肯定是让排序后中位数右边的数尽可能大,并且左边的数也尽可能大,这样的话平均数也会变大。如果我们要枚举每个数是中位数的话,再枚举长度就是n^2的时间复杂度了,所以要优化。但是我们发现,随着长度变长,新加进来的两个数的和一定是越来越小的:
在这里插入图片描述
所以这个函数的曲线是这样的:
在这里插入图片描述
三分的图,但是对于诶个点是整数的时候,可以用二分代替三分:比较mid和mid-1的大小即可。
但是不能直接求平均数,会有精度的问题,所以用交叉相乘即可。

偶数

对于偶数的情况,我们考虑这是否可能,因为如果不可能的话就不用做了哈哈
首先我们假设左边的中位数是al,右边的中位数是ar,数的数量是s,那么现在的答案是 1 + . . + a l + a r + . . . + a s s a l + a r 2 \frac{1+..+al+ar+...+as}{s}-\frac{al+ar}{2}
如果将ar去掉,答案变成 1 + . . . + a l + . . + a s s 1 a l \frac{1+...+al+..+as}{s-1}-al 用上面的-下面的,就变成了
( s 1 ) a r ( a 1 + . . . + a l + . . . + a s ) s ( s 1 ) a r a l 2 \frac{(s-1)*ar-(a1+...+al+...+as)}{s*(s-1)}-\frac{ar-al}{2}
用高数的那种什么方法,就是说一个数变小之后还是大于等于另一个数,那么这个数就大雨另一个数。
所以因为2是一定小于等于s*(s-1)的,所以我们假设右边变成 a r a l s ( s 1 ) \frac{ar-al}{s*(s-1)} ,那么就变成了
( s 1 ) a r + a l ( a 1 + . . . + a l + a r + . . . + a s ) s ( s 1 ) \frac{(s-1)*ar+al-(a1+...+al+ar+...+as)}{s*(s-1)} ,那么可以看成 ( s 1 ) a r + a l (s-1)*ar+al ( a 1 + . . . + a l + a r + . . . + a s ) (a1+...+al+ar+...+as)这两个数的比较 ,那么变成 ( s 1 ) a r (s-1)*ar a 1 + . . . + a r + . . . + a s a1+...+ar+...+as 这两个数的比较,于是又变成
a r ar a 1 + . . . + a r + a s s 1 \frac{a1+...+ar+as}{s-1} 这两个数的比较,于是我们可以看出,ar是 a 1 + . . . + a r + . . . + a s a1+...+ar+...+as 的中位数(因为al已经被消掉了),所以这两个数就是平均数与中位数的大小比较,同时我们知道,平均数应该一定大于等于中位数,否则你所求的东西将毫无意义。于是我们可以得出,奇数一定比偶数更优。
于是不用考虑偶数的情况。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+5;
ll a[N],pre[N];
int n;
ll check(int p,int len)
{
    return pre[p]-pre[p-len-1]+pre[n]-pre[n-len];
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++)
        pre[i]=pre[i-1]+a[i];
    int p=1,len=0;
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        int l=1,r=min(i-1,n-i),mid;
        while(r>=l)
        {
            mid=l+r>>1;
            if((ll)check(i,mid)*(mid*2-1)>=(ll)check(i,mid-1)*(mid*2+1))
            {
                l=mid+1;
                if((ll)check(i,mid)*(len*2+1)-a[i]*(len*2+1)*(mid*2+1)>(ll)ans*(mid*2+1)-a[p]*(len*2+1)*(mid*2+1))
                    ans=check(i,mid),p=i,len=mid;
            }
            else
                r=mid-1;
        }
    }
    printf("%d\n",len*2+1);
    for(int i=p-len;i<=p;i++)
        printf("%d ",pre[i]-pre[i-1]);
    for(int i=n-len+1;i<=n;i++)
        printf("%d ",pre[i]-pre[i-1]);
    printf("\n");
    return 0;
}

发布了530 篇原创文章 · 获赞 31 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/103197478
今日推荐