CF1993D Med-imize 题解
题意
给定一个长度为 \(n\) 的序列 \(a\),每次删除其中一个长度为 \(k\) 的子段直到序列长度小于等于 \(k\),最大化操作完之后序列的中位数。
思路
首先转化一下求解中位数,令当前中位数为 \(x\),我们构造一个辅助数组 \(b\),满足 \(x\le a_i\) 时 \(b_i=1\),否则 \(b_i=-1\).
那么 \(b\) 中元素的和一定大于 \(0\).
所以我们可以二分中位数的值,使用 dp 进行 check:
定义 \(dp_i\) 代表处理完 \(b_1\sim b_i\) 后 \(\sum_{j=1}^ib_i\) 的最大值,则有:
- \(i-1\pmod k=0\),\(dp_i=\max(dp_{i-k},b_i)\).
- otherwise,\(dp_i=\max(dp_{i-1}+b_i,dp_{i-k})\).
code
#include <bits/stdc++.h>
#define chmax(x, y) x = max(x, y)
#define chmin(x, y) x = min(x, y)
#define SP << " " <<
#define fish signed
using namespace std;
mt19937 rnd(1209);
const int N = 5e5 + 10;
int a[N], b[N], n, k, dp[N];
bool check(int x)
{
for(int i = 1; i <= n; i ++) {dp[i] = -1; if(a[i] >= x) b[i] = 1; else b[i] = -1;}
dp[1] = b[1];
for(int i = 2; i <= n; i ++)
{
if(i % k == 1 || k == 1) dp[i] = max(dp[i - k], b[i]);
else
{
dp[i] = dp[i - 1] + b[i];
if(i > k) chmax(dp[i], dp[i - k]);
}
}
return dp[n] > 0;
}
void solve()
{
int mxa = 0; cin >> n >> k;
for(int i = 1; i <= n; i ++) cin >> a[i], chmax(mxa, a[i]);
int l = 1, r = mxa, res = 0;
while(l <= r)
{
int mid = l + r >> 1;
if(check(mid)) l = mid + 1, res = mid;
else r = mid - 1;
} cout << res << "\n";
}
fish main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int t; cin >> t;
while(t --) solve();
return 0;
}

浙公网安备 33010602011771号