D. Med-imize
D. Med-imize
Given two positive integers $n$ and $k$, and another array $a$ of $n$ integers.
In one operation, you can select any subarray of size $k$ of $a$, then remove it from the array without changing the order of other elements. More formally, let $(l, r)$ be an operation on subarray $a_l, a_{l+1}, \ldots, a_r$ such that $r-l+1=k$, then performing this operation means replacing $a$ with $[a_1, \ldots, a_{l-1}, a_{r+1}, \ldots, a_n]$.
For example, if $a=[1,2,3,4,5]$ and we perform operation $(3,5)$ on this array, it will become $a=[1,2]$. Moreover, operation $(2, 4)$ results in $a=[1,5]$, and operation $(1,3)$ results in $a=[4,5]$.
You have to repeat the operation while the length of $a$ is greater than $k$ (which means $|a| \gt k$). What is the largest possible median$^\dagger$ of all remaining elements of the array $a$ after the process?
$^\dagger$The median of an array of length $n$ is the element whose index is $\left \lfloor (n+1)/2 \right \rfloor$ after we sort the elements in non-decreasing order. For example: $median([2,1,5,4,3]) = 3$, $median([5]) = 5$, and $median([6,8,2,4]) = 4$.
Input
The first line contains a single integer $t$ ($1 \le t \le 10^4$) — the number of test cases.
The first line of each test case contains two integers $n$ and $k$ ($1 \le n, k \le 5 \cdot 10^5$).
The second line contains $n$ integers $a_1, a_2, \ldots, a_n$ ($1 \le a_i \le 10^9$) — the array $a$.
It is guaranteed that the sum of $n$ over all test cases does not exceed $5 \cdot 10^5$.
Output
For each test case, print a single integer — the largest median possible after performing the operations.
Example
Input
5
4 3
3 9 9 2
5 3
3 2 5 6 4
7 1
5 9 2 6 5 4 6
8 2
7 1 2 6 8 3 4 5
4 5
3 4 5 6
Output
3
4
9
6
4
Note
In the first test case, you can select a subarray $(l, r)$ which can be either $(1, 3)$ or $(2, 4)$. Thus, two obtainable final arrays are $[3]$ and $[2]$. The former one has the larger median ($3 > 2$) so the answer is $3$.
In the second test case, three obtainable final arrays are $[6, 4]$, $[3, 4]$, and $[3, 2]$. Their medians are $4$, $3$, and $2$ respectively. The answer is $4$.
In the third test case, only one element is left in the final array and it can be any element of the initial array. The largest one among them is $9$, so the answer is $9$.
解题思路
好久没做过中位数的题了,结果赛时罚坐了一个多小时都没做出来。卡了很久才想到可以二分,但把小于二分值的 $a_i$ 设成了 $0$,其余设成 $1$,然后就是贪心找一定数量的 $0$ 和 $1$ 结果死活过不了。看题解才知道应该把小于二分值的 $a_i$ 设成 $-1$,并且选出来的下标在模 $k$ 意义下是是依次加 $1$ 的,有了这些提示就会做了,真是菜到炸了。
题目可以转换成选出 $\left((n - 1) \bmod k\right) + 1$ 个数(下面记为 $m$),假设对应的下标为 $i_0, \ldots i_{m-1}$,相邻两个下标之间需要间隔 $c \cdot k \, (c \geq 0)$ 个元素,即 $i_{j+1} - i_j = c \cdot k + 1$。
对于涉及中位数的题可以考虑二分,对于二分值 $\text{mid}$,如果 $a_i \geq \text{mid}$ 则设为 $w_i = 1$,否则设为 $w_i = -1$。这样如果选出的 $m$ 个数的中位数大于等于 $\text{mid}$,那么对应的 $w_i$ 的和必定大于 $0$。因此选出的 $m$ 个数对应的 $w_i$ 的和应该尽可能大,此时可以考虑 dp了。
选择的下标之间满足什么样的关系呢?可以知道选出的第一个数的下标 $i_0$ 必定满足 $i_0 \bmod k = 0$,并且由于 $i_1 - i_0 = c \cdot k + 1$,因此有 $i_1 \bmod k = 1$。进而发现对于选出的每个下标都有 $i_j \bmod k = j$。
定义 $f(i)$ 表示在前 $i$ 个数中选择了 $(i \bmod k) + 1$ 个数,且 $a_i$ 作为第 $(i \bmod k) + 1$ 个数,关于 $w_i$ 的和的最大值,状态转移方程为 $$\begin{cases} f(i) = w_i &, i \bmod k = 0 \\ f(i) = \max\limits_{\begin{array}{c} j<i \\ j \bmod k = (i \bmod k) - 1 \end{array}}\{f(j)\}+ w_i &, i \bmod k > 0 \end{cases}$$
可以用一个 $g(j) = \max\limits_{i \bmod k = j}\{f(i)\}$ 记录前缀最大值来加速转移。
最后答案就是 $\max\limits_{i \bmod k = m-1}\{f(i)\} = g(m-1)$。
AC 代码如下,时间复杂度为 $O(n \log{A})$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e5 + 5;
int n, m;
int a[N];
int f[N], g[N];
bool check(int mid) {
memset(g, -0x3f, (n - 1) % m + 1 << 2);
for (int i = 0; i < n; i++) {
int w = a[i] >= mid ? 1 : -1;
if (i % m == 0) f[i] = w;
else f[i] = g[i % m - 1] + w;
g[i % m] = max(g[i % m], f[i]);
}
return g[(n - 1) % m] > 0;
}
void solve() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int l = 1, r = *max_element(a, a + n);
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
cout << l << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
参考资料
Editorial of Codeforces Round 963 (Div. 2):https://codeforces.com/blog/entry/132185
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18344229