链接:ECJTU 2018 Summer Training 1 - Virtual Judge https://vjudge.net/contest/236677#problem/G
谷歌翻译:
距离特工Mahone离开安曼还有K小时!哈姆穆里不喜欢任务中的事情,他不想再次失败。有些地方的学生太多,而其他地方只有很少的学生。
每当Hammouri命令学生改变他的位置时,学生只需要一个小时就能到达新的地方。 Hammouri等到他确定学生在发出新命令之前已到达新地方。因此,每小时只有一名学生可以改变他的位置。
Hammouri希望命令学生改变他们的位置,以便在K小时后,覆盖同一地方的学生的最大数量被最小化。
考虑到覆盖每个地方的学生人数,您的任务是找到K小时后覆盖同一地点的最大学生人数,假设Hammouri正确地最小化了这个数字。
输入
第一行输入包含两个整数M(2≤M≤105)和K(1≤K≤109),其中M是位数,K是代理Mahone离开安曼之前剩余的小时数。
第二行包含M个非负整数,每个整数代表覆盖其中一个地方的学生人数。每个地方最多有109名学生。
产量
假设Hammouri在最近K小时内尽可能地减少了这个数字,打印在K小时后覆盖一个地方的学生的最大数量。
应该看得懂吧。
我们要算在小于等于k次操作后所有地方学生的最大值。
个人思路:我们把所有的值的和sum算出,可以知道,如果sum%M==0,那么学生数ave最小为sum/M,否则最小为sum/M+1;
然后用二分,最小为l=ave,最大就是r=max(M1,...Mi),不断二分查找符合条件的值,同时不断更新就可以了。
时间复杂度为nlogn吧
#include<iostream> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define inf 1000000009 ll a[100005]; ll n,m,ans,ave; int jug(ll k)//判断是否可行 { ll count=0; for(int i=0;i<n;i++) { if(a[i]>k) count+=a[i]-k; } if(count>m) return 0; return 1; } void binary(ll l,ll r) { ll mid=(l+r)/2; while(l<=r) { if(jug(mid)) { ans=min(ans,mid); r=mid-1; } else l=mid+1; mid=(l+r)/2; } } int main() { while(cin>>n>>m) { ll sum=0; ans=inf; ll max=0; for(int i=0;i<n;i++) { cin>>a[i]; sum+=a[i]; if(a[i]>max) max=a[i]; } if(sum%n==0)//找最小值 ave=sum/n; else ave=sum/n+1; binary(ave,max); cout<<ans<<endl; } return 0; }