Codeforce 1201C 二分

原题链接:http://codeforces.com/contest/1201/problem/C

题意:给出n个数(n为奇数),每一次操作可以将任意一个数加一,给出操作数,求这组数的中位数最大是多少。

思路:枚举中位数。数组由小到大排序后,从第n/2+1到第最后一个(因为是找最大中位数,所以数组前一半可以不管),遍历每一个数与当前中位数的差,将这些差作和,就是达到当前中位数所需要的操作次数,找到符合条件的最大中位数(条件即为操作次数小于规定次数)。

细节:

bool check(ll mid){
    ll s=0;
    for(int i=n/2;i<n;i++){
        if(a[i]<mid) s+=mid-a[i];
    }
    return s<=k;
}

当前中位数所需的操作数和,返回是否满足小于规定的操作数。

    ll l=0,r=3e9;
    while(l<r){
        ll mid=(l+r+1)/2;
        if(check(mid)){
            l=mid;
        }
        else{
            r=mid-1;
        }
    }

1.若满足小于规定操作数,则将当前中位数赋给l,下一次增加l的大小到mid看是否符合条件,如此往复;若不符合,退让一步,将mid-1赋给r,下一次得到更小的mid,同上往复。可以理解成大步向前,小步退后,因为找的是可能的最大值。

2.r的初始值要保证大于所有的结果,题中k最大1e9,a[i]最大也是1e9,操作是加一,所以加起来即可,再随便往大写一点(2e9也可以A)。

3.mid=(l+r+1)/2,因为int除法是向下取整,所以式子和mid=(l+r)/2+1是一样的。

完整代码:

#include <iostream>
#include <algorithm>
using namespace std;
#define N 200010

typedef long long ll;
ll a[N],n,k;
bool check(ll mid){
    ll s=0;
    for(int i=n/2;i<n;i++){
        if(a[i]<mid) s+=mid-a[i];
    }
    return s<=k;
}
int main(int argc, char** argv) {
    scanf("%lld%lld",&n,&k);
    for(int i=0;i<n;i++){
        scanf("%lld",&a[i]);
    }
    sort(a,a+n);
    ll l=0,r=3e9;
    while(l<r){
        ll mid=(l+r+1)/2;
        if(check(mid)){
            l=mid;
        }
        else{
            r=mid-1;
        }
    }
    printf("%lld\n",l);
    return 0;
}

 

posted @ 2019-08-23 10:35  ogada_567  阅读(112)  评论(0)    收藏  举报