1 条题解
-
0
题目题解
问题理解
给定一个长度为 (奇数)的数组 ,每次操作可以将任意元素加 ,最多操作 次。
求操作后可能的最大中位数。
第一步:排序
设排序后的数组为 。
中位数是 ,即中间元素。
我们只能通过增加元素来改变中位数,且只影响中间及后面的元素。
第二步:二分答案
由于答案具有单调性:若中位数可以达到 ,则比 小的数也一定可以达到。
因此可以二分中位数 。对于给定的 ,我们需要将 中所有小于 的数提升到 。
$$\text{need}(x) = \sum_{i = (n+1)/2}^{n} \max(0, x - b_i). $$
需要的操作次数为:若 ,则 可行;否则不可行。
第三步:二分范围
下界:当前中位数 。
上界:(因为最多将中位数增加 )。
第四步:时间复杂度
- 排序:。
- 每次二分检查 。
- 二分次数 。
- 总复杂度 ,满足 。
代码实现
#include <bits/stdc++.h> using namespace std; using ll = long long; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, k; cin >> n >> k; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } sort(a.begin(), a.end()); int mid = n / 2; // 中位数下标(0-indexed) ll l = a[mid], r = a[mid] + k, ans = a[mid]; while (l <= r) { ll x = (l + r) / 2; ll need = 0; for (int i = mid; i < n; i++) { if (a[i] < x) { need += x - a[i]; if (need > k) break; } } if (need <= k) { ans = x; l = x + 1; } else { r = x - 1; } } cout << ans << "\n"; return 0; }
验证样例
输入:
3 2 1 3 5排序后 ,中位数下标 ,。
二分:- ,需要 ,可行。
- ,需要 ,不可行。
输出 。
输入:
5 5 1 2 1 1 1排序后 ,中位数下标 ,。
二分得 ,需要 ,可行。
输出 。输入:
7 7 4 1 2 4 3 4 4排序后 ,中位数下标 ,。
二分得 ,需要 ,可行。
输出 。与题目输出一致。
总结
本题的关键在于:
- 排序后,中位数只可能通过增加中间及后面的元素来提升。
- 使用二分答案,检查将后半段所有小于 的元素提升到 所需操作数是否 。
- 时间复杂度 。
- 1
信息
- ID
- 6344
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 2
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者