您的位置:首页 > 其它

codeforces 671B Robin Hood 二分

2016-05-12 14:08 246 查看
题意:有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
,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\n",ans2-ans1);
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: