题意:给你N个人的财富值,每天最有钱的人会给最没钱的人一块钱,问K天之后,最穷的人和最富有的人之间差多少钱。
思路:二分确定k天后的最大值和最小值,二分的上下界要注意一下,如果sum能被n整除,最小值下界为一开始最小的,上界为sum/n,最大值下届为
sum/n,上界为一开始最大的;如果不能被整除,最小值下界仍为一开始最小的,上界为sum/n,但最大值的下界为sum/n+1,上届为一开始最大的。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6+5;
ll a[maxn], n, k;
bool judge1(ll x)
{
ll tmp = 0;
for(int i = 1; i <= n; i++)
if(a[i] < x) tmp += x-a[i];
return tmp <= k;
}
bool judge2(ll x)
{
ll tmp = 0;
for(int i = 1; i <= n; i++)
if(a[i] > x) tmp += a[i]-x;
return tmp <= k;
}
int main(void)
{
while(cin >> n >> k)
{
ll sum = 0;
ll l1 = INF, r1, l2, r2 = -INF;
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]), sum += a[i], l1 = min(l1, a[i]), r2 = max(r2, a[i]);
r1 = sum/n;
ll ans1 = l1, ans2;
while(l1 <= r1)
{
ll mid = (l1+r1)/2;
if(judge1(mid)) l1 = mid+1, ans1 = mid;
else r1 = mid-1;
}
if(sum%n == 0) l2 = sum/n;
else l2 = sum/n+1;
while(l2 <= r2)
{
ll mid = (l2+r2)/2;
if(judge2(mid)) r2 = mid-1, ans2 = mid;
else l2 = mid+1;
}
printf("%lld\n", ans2-ans1);
}
return 0;
}