NYOJ  2354-分班级(二分)_二分

题解:一道简单题,之前一直想歪了,set,优先队列都试过,简直年轻,其实直接两次二分就行了,一次二分最小值,一次二分最大值。(注意上下界)

#include<set>  
#include<map>         
#include<stack>                
#include<queue>                
#include<vector>        
#include<string>      
#include<math.h>       
#include<stdio.h>                
#include<iostream>                
#include<string.h>                
#include<stdlib.h>        
#include<algorithm>       
#include<functional>        
using namespace std;
typedef long long ll;
#define inf 1000000000           
#define mod 1000000007                 
#define maxn  500005     
#define PI 3.1415926  
#define lowbit(x) (x&-x)     
#define eps 1e-9   
ll a[maxn], n, k;
bool check1(ll x)
{
	int i;
	ll res = 0;
	for (i = 1;i <= n;i++)
		if (a[i] < x)
			res += x - a[i];
	if (res <= k)
		return 1;
	return 0;
}
bool check2(ll x)
{
	int i;
	ll res = 0;
	for (i = 1;i <= n;i++)
		if (a[i] > x)
			res += a[i] - x;
	if (res <= k)
		return 1;
	return 0;
}
int main(void)
{
	ll  i, j, ans1, ans2, tmp, l, r, sum, mid;
	while (scanf("%lld%lld", &n, &k) != EOF)
	{
		ans1 = 0;sum = 0;ans2 = 0;
		for (i = 1;i <= n;i++) 
			scanf("%lld", &a[i]), sum += a[i];
		ll mx = sum / n;l = 1, r = mx;
		while (l <= r)
		{
			mid = (l + r) / 2;
			if (check1(mid))
			{
				ans1 = mid;
				l = mid + 1;
			}
			else
				r = mid - 1;
		}
		if (sum%n) mx++;
		l = mx;r = sum;
		while (l <= r)
		{
			mid = (l + r) / 2;
			if (check2(mid))
			{
				ans2 = mid;
				r = mid - 1;
			}
			else
				l = mid + 1;
		}
		printf("%lld\n", ans2 - ans1);
	}
	return 0;
}