1. 题目来源
链接:3578. 最大中位数
2. 题目解析
二分答案。但是我貌似每次都看不出来。
首先本题是要求一个答案中位数。其次,中位数要尽量大。中位数显然不能取特别大,有条件限制,给定一个可能中位数 x
的时候,我们只需要判断后半段能否在 k
次内变到 x
即可。这个
O
(
n
)
O(n)
O(n) 即可进行判断。
故二分答案是 O ( l o g n ) O(logn) O(logn),判断 O ( n ) O(n) O(n)。
细节:
- 注意本题计算
mid
时需要开long long
,中间计算过程会爆int
。当n=1 a[0]=1e9 k=1e9
时,中位数可以到2e9
,计算mid
时将爆int
。 - 本题要求小于等于
k
操作次数均可,注意check()
的条件判断。一开始写成了cnt > k
将r=mid
更新过来,这是错误的。当cnt > k
意味着当前mid
是不能做中位数的,应该更新为r=mid-1
,一定注意!
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
空间复杂度: O ( n ) O(n) O(n)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, k;
int a[N];
bool check(int mid) {
long long cnt = 0; // 在这要开 long long 记录
for (int i = n >> 1; i < n; i ++ )
if (a[i] < mid)
cnt += mid - a[i];
return cnt <= k;
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
sort(a, a + n);
int l = 0, r = 2e9;
while (l < r) {
int mid = 1ll + l + r >> 1; // 在这中间过程转 long long
if (check(mid)) l = mid;
else r = mid - 1;
}
printf("%d\n", l);
return 0;
}