题目传送门
思路:
这道题要求中位数最大,我们一个一个去试肯定会TLE的,所以我们就要用到一些贪心思想。
贪心:
先看一组数据:
1 1 1000 999 1000
中位数:999
我们可以发现,虽然1很小,但是由于其他的数很大,大的数有三个,小的数有两个,那两个数对中位数没用影响,所以为了让中位数最大,我们要将前一半比较大的数加到很大,不用管后一半较小的数。
再看看怎么加更合适:
再看一组数据:
5 4
1 2 4 6 7
最大中位数:7
我们将4加到7,将6加到7,所以我们发现要想让中位数最大,就要让前一半的数尽可能的接近。
我们已经有了思路,但是一个一个去试中位数的大小,看看是否可以,那么时间复杂度是
O(),也会超时,这里我们就要用二分了。
二分:
二分模板:
int l=1,r=2000000000,mid;
while(l<=r){
mid=((long long)l+r)/2;
if(check(mid))l=mid+1;
else r=mid-1;
}cout<<r;
check函数:
我们可以从中间开始遍历一遍数组,用ans统计一共加了多少数,如果a[i]<mid,那么就让ans减伤它与mid的差,否则就break(我们已经排好了序,后面的只会大于等于mid),最后判断一下ans是否大于k即可。
bool check(int mid){
int pos=n/2+1;
long long cnt=0;
for(int i=pos;i<=n;i++){
if(a[i]>=mid)break;
cnt+=(mid-a[i]);
}if(cnt<=k)return true;return false;
}
完整代码:
#include<iostream>
#include<algorithm>
using namespace std;
int n,k,a[201000];
bool check(int mid){
int pos=n/2+1;
long long cnt=0;
for(int i=pos;i<=n;i++){
if(a[i]>=mid)break;
cnt+=(mid-a[i]);
}if(cnt<=k)return true;return false;
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n);
int l=1,r=2000000000,mid;
while(l<=r){
mid=((long long)l+r)/2;
if(check(mid))l=mid+1;
else r=mid-1;
}cout<<r;
return 0;
}