题意:n个人,每个人ci的金币,每天最富有的人都会给最贫穷的人1金币,问k天后最富有人和最贫穷的人差了多少金币。
题解:
假设每天最多金币的一人减少一个金币 不翼而飞 二分出金币的最大值
同理计算出最小值
如果最小值大于等于最大值 就代表进入了循环状态 最大最小相差小于1 所以判断一下sum是否能整除n 如果能 答案是0 否则是1
如果不大于 就直接输出最大值最小值
二分的方法是:对于一个mid 我们求出至少有一个金币是mid+1的天数是多少 至少有一个金币为mid-1的天数是多少
那么只要判断k是否在这个区间即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll a[500005],k,n;
ll check(ll t){
ll num1=0,num2=0;
for(ll i=1;i<=n;i++){
num1+=max(a[i]-(t),0LL);
num2+=max(a[i]-(t-1),0LL);
}
num1--;
if(num1<k&&num2>k)return 1;
if(num1>=k)return -1;
if(num2<=k)return 0;
}
ll checks(ll t){
ll num1=0,num2=0;
for(ll i=1;i<=n;i++){
num1+=max((t)-a[i],0LL);
num2+=max((t+1)-a[i],0LL);
}
num1--;
if(num1<k&&num2>k)return 1;
if(num1>=k)return -1;
if(num2<=k)return 0;
}
int main(){
ll i;
scanf("%lld%lld",&n,&k);
ll da=0,xiao=1000000,sum=0;
for(i=1;i<=n;i++)scanf("%lld",&a[i]),da=max(da,a[i]),xiao=min(xiao,a[i]),sum+=a[i];
ll l=xiao,r=da;
ll mas;
while(l+1<r){
ll mid=(l+r)/2;
ll d=check(mid);
if(d==1){
r=mid;
break;
}
if(d==-1)l=mid;
else r=mid;
}
if(check(r))mas=r;
else mas=l;
l=xiao;
r=da;
while(l+1<r){
ll mid=(l+r)/2;
ll d=checks(mid);
if(d==1){
l=mid;
break;
}
if(d==-1)r=mid;
else l=mid;
}
ll o;
if(check(l))o=l;
else o=r;
if(o>=mas){
if(sum%n)printf("1\n");
else printf("0\n");
}
else printf("%lld\n",mas-o);
return 0;
}