1 条题解
-
0
题目解析
给定数组 (元素在 到 之间)和整数 ,定义 是子中位数如果存在长度 的子数组,使得 是该子数组的一个中位数(按题目中的中位数定义)。需要找到最大的子中位数 并输出任意一个对应的子数组。
关键观察
- 对于固定的 ,定义 若 ,否则 。则子数组 满足 的元素数量 当且仅当 。
- 如果 是子数组的中位数,则它同时满足 的数量 和 的数量 。但可以证明,对于最大可能的 ,只需要检查第一个条件即可(因为此时第二个条件自动成立)。
- 因此,最大子中位数等于最大的 使得存在长度 的子数组,其 。这是一个典型的“存在长度至少为 的子数组和非负”问题。
算法步骤
- 二分答案 ,范围 。
- 对于每个 ,构造数组 : 若 ,否则 。
- 计算前缀和 ,。
- 遍历右端点 从 到 :
- 维护前 个前缀和的最小值 及其对应的位置 (即最小的 )。
- 若 ,则存在满足条件的子数组 。
- 同时记录该 可行,并保存区间。
- 二分找到最大的可行 ,然后输出对应的 和区间。
时间复杂度: 每个测试用例,总和 ,,可以通过。
代码实现
#include <bits/stdc++.h> using namespace std; using ll = long long; int main() { ios::sync_with_stdio(false); cin.tie(0); int t; cin >> t; while (t--) { int n, k; cin >> n >> k; vector<int> a(n); for (int i = 0; i < n; ++i) cin >> a[i]; int lo = 1, hi = n; int ans_v = 1, ans_l = 0, ans_r = 0; while (lo <= hi) { int mid = (lo + hi) / 2; vector<int> b(n); for (int i = 0; i < n; ++i) b[i] = (a[i] >= mid) ? 1 : -1; vector<int> pref(n + 1); pref[0] = 0; for (int i = 0; i < n; ++i) pref[i+1] = pref[i] + b[i]; int min_pref = pref[0]; int min_pos = 0; bool ok = false; int best_l = -1, best_r = -1; for (int r = k; r <= n; ++r) { // 维护前 r-k 个前缀的最小值 // 当 r 增加时,新的候选 l-1 = r-k int idx = r - k; if (pref[idx] < min_pref) { min_pref = pref[idx]; min_pos = idx; } if (pref[r] >= min_pref) { ok = true; best_l = min_pos + 1; // 注意下标从1开始 best_r = r; break; } } if (ok) { ans_v = mid; ans_l = best_l; ans_r = best_r; lo = mid + 1; } else { hi = mid - 1; } } cout << ans_v << " " << ans_l << " " << ans_r << "\n"; } return 0; }
- 1
信息
- ID
- 7106
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者