题意:有n个人,每个人a[i]个物品,进行k次操作,每次都从最富有的人手里拿走一个物品给最穷的人
问k次操作以后,物品最多的人和物品最少的人相差几个物品
分析:如果次数足够多的话,最后的肯定在平均值上下,小的最多被补到sum/n,大最多减少到sum/n,或者sum/n+1
然后就二分最小值,看所有小的是否能在k次被填满
二分最大值,看所有大的是否都在k次被抹平
然后就是二分的写法,小和大的不一样,需要加等号,避免死循环
#include <stdio.h> #include <string.h> #include <algorithm> #include <math.h> using namespace std; typedef long long LL; const int N = 5e5+5; int a[N],k,n; bool checkmax(int x){ int tmp=k; for(int i=1;i<=n;++i){ if(a[i]>x)tmp-=(a[i]-x); if(tmp<0)return false; } return true; } bool checkmin(int x){ int tmp=k; for(int i=1;i<=n;++i){ if(a[i]<x)tmp-=(x-a[i]); if(tmp<0)return false; } return true; } int main(){ scanf("%d%d",&n,&k); LL sum=0; int k1,k2,x=0,y=0x7f7f7f7f; for(int i=1;i<=n;++i){ scanf("%d",&a[i]); sum+=a[i]; x=max(x,a[i]); y=min(y,a[i]); } k1=k2=sum/n; if(sum%n)++k2; int ans2,ans1,l=y,r=k1; while(l<=r){ int m=(l+r)>>1; if(checkmin(m))ans1=m,l=m+1; else r=m-1; } l=k2,r=x; while(l<r){ int m=(l+r)>>1; if(checkmax(m))r=m; else l=m+1; } ans2=(l+r)>>1; printf("%d ",ans2-ans1); return 0; }