分班级(经典二分)

题目描述

        Zoro是一个有强迫症的人,他喜欢均衡。
17级的新生要开学了,起初所有班级是按照学生的来源地分的,各班人数非常不合理。于是老师要求Zoro来让各班人数均衡一下。
        由于学校系统陈旧,每次调换只能是Zoro自己手动的把一个学生从一个班级拉到另外一个班级,由于Zoro有强迫症,他每次会找出班级人数最多的那个拉出一个人转到一个人数最少的班级,而且每次操作,耗费一次权限,而他的账号只有k次权限。老师最后会看所有班级人数差的最大值。
由于班级实在太多,Zoro要做完需要很长时间,你能不能帮助Zoro先计算出他工作完成后所有班级人数差的最大值报告给老师。

输入

第一行输入两个整数n和k,分别代表班级数量和Zoro账号的操作权限次数。
接下来一行n个整数 第i个数字代表第i个班级有ci个人。
(1<=n<=500000,0<=k<=1e9,0<= ci <=1e9)

输出

输出一个整数表示最后所有班级人数差的最大值。

样例输入

5 1
1 2 3 4 5

样例输出

2
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N=500005;
LL a[N],n;
LL ok1(LL mid)
{
    LL i,sum=0;
    for(i=1; i<=n; i++)
    {
        if(a[i]>=mid)
            break;
        sum=sum+mid-a[i];
    }
    return sum;
}
LL ok2(LL mid)
{
    LL i,sum=0;
    for(i=n; i>=1; i--)
    {
        if(a[i]<=mid)
            break;
        sum=sum+a[i]-mid;
    }
    return sum;
}
int main()
{
    LL i,k;
    while(~scanf("%lld%lld",&n,&k))
    {
        for(i=1; i<=n; i++)
            scanf("%lld",&a[i]);
        sort(a+1,a+1+n);
        LL l=a[1],r=a[n],mid;
        //二分min
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(ok1(mid)<=k)
                l=mid+1;
            else
                r=mid-1;
        }
        LL min1=r;
        l=a[1],r=a[n];
        //二分max
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(ok2(mid)<=k)
                r=mid-1;
            else
                l=mid+1;
        }
        LL max1=l;
        printf("%lld
",max1-min1);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lesroad/p/9469288.html