题目链接:http://codeforces.com/gym/100989/problem/G
题意:给出m个数,最多经过k次操作,每次操作只能把其中一个数减一,同时另一个数加一,使得这m个数的最大值最小,并且输出这个最大值。
解题思路:首先我们很容易想到:这m个数的平均值ave一定可以使它们的最大值最小,但是前提是必须在k次操作以内完成,同时这个值一定小于这m个数中的最大值maxs。所以我们得到答案的取值范围ave<=ans<=maxs.
在这个区间二分:
首先取中间值mid=(ave+maxs)/2,如果经过k次以内的操作可以使最大值等于mid,那么答案的取值范围为:ave<=ans<=mid。否者mid+1<=ans<=maxs。依次循环。
代码如下:
#include<iostream>
#include<stdio.h>
#include<string>
using namespace std;
const int inf=1e9+9;
const int maxn=1e5+9;
typedef long long ll;
int s[maxn];
bool jug(int Ans, int m, int k)
{
int count=0;
int i;
for(i=0;i<m;i++)
{
if(Ans<s[i])
count+=s[i]-Ans;
if(count>k)
return false;
}
return true;
}
void bin(int & ans,int maxs,int m, int k)
{
int mid=(ans+maxs)/2;
while(ans<maxs)
{
if(jug(mid,m,k))
maxs=mid;
else
ans=mid+1;
mid=(ans+maxs)/2;
}
return ;
}
int main()
{
int m,k,i;
cin>>m>>k;
int maxs=0;
ll sum=0;
int ans;
for(i=0;i<m;i++)
{
cin>>s[i];
maxs=max(s[i],maxs);
sum+=s[i];
}
if(sum%m==0)
ans=sum/m;
else
ans=(sum/m)+1;
bin(ans,maxs,m,k);
cout<<ans<<endl;
return 0;
}