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\) 的最大值,则有:

  1. \(i-1\pmod k=0\)\(dp_i=\max(dp_{i-k},b_i)\).
  2. 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;
}
posted @ 2024-11-27 11:21  lfyszy  阅读(34)  评论(0)    收藏  举报