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