Codeforces 671B Robin Hood (二分)

Robin Hood

有n(<=500000)个人有各自的财富,Robin Hood要劫富济贫,每次把最富有的那个人的财富抢去1,加在最穷的那个人的财富里,但是一共只能抢有限次数,问最后最富有的那个人和最穷的那个人财富差的最小值。

要让最富有与最穷的差值最小,也就是要让一个最大值最小,最小值最大,用最大值最小-最小值最大那么就是最小,那么求这两个值就可以用二分.

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL long long
using namespace std;

const int maxn = 500010;
LL n,k,a[maxn],pre[maxn],sum,mini,maxi,ave;

int checkp(LL x) {
	int p = lower_bound(a+1,a+n+1,x)-a-1;
	if(p*x-pre[p] > k)return 0;//***
	else return 1;
}

int checkr(LL x) {
	int p = upper_bound(a+1,a+1+n,x)-a;
	if(pre[n]-pre[p-1]-(n-p+1)*x > k)return 0;//*****
	else return 1;
}

int main() {
	scanf("%I64d%I64d",&n,&k);
	for(int i = 1; i <= n; ++i)scanf("%I64d",&a[i]);
	sort(a+1,a+n+1);
	for(int i = 1; i <= n; ++i) {
		sum += a[i];
		pre[i] = pre[i-1]+a[i];
	}
	ave = sum / n;
	LL l = a[1],r = ave+1;
	while(l+1 < r) {
		LL mid = (l+r)/2;
		if(checkp(mid))l = mid;
		else r = mid;
	}
	mini = l;
	l = ave,r = a[n];if(sum%n)++l;
	while(l < r) {
		LL mid = (l+r)/2;
		if(checkr(mid))r = mid;
		else l = mid+1;
	}
	maxi = l;

	printf("%I64d
",maxi-mini);
	return 0;
}

  

原文地址:https://www.cnblogs.com/xgtao984/p/5720165.html