Codeforces Round #703 Div2 D. Max Median 二分答案

Codeforces Round #703 Div2 D. Max Median 二分答案


传送门: https://codeforces.com/contest/1486/problem/D

题意

给 一 个 长 度 为 n 的 数 组 , 在 里 面 找 若 干 个 长 度 ≥ k 的 区 间 , 问 这 些 区 间 中 最 大 的 中 位 数 是 多 少 。 给一个长度为n的数组,在里面找若干个长度\ge k的区间,问这些区间中最大的中位数是多少。 nk
中 位 数 , 请 输 出 最 大 值 。 \red{中位数},请输出最大值。

思路

依 靠 我 们 小 学 二 年 级 的 知 识 , 将 一 个 序 列 排 序 后 , 中 位 数 为 中 间 的 数 字 。 依靠我们小学二年级的知识,将一个序列排序后,中位数为中间的数字。
奇 数 则 为 ( n + 1 ) 2 , 偶 数 为 n 2 处 。 奇数则为\frac{(n+1)}{2},偶数为\frac{n}{2}处。 2(n+1)2n
所 以 不 管 奇 偶 , 都 会 有 一 半 ( ≥ ) 中 位 数 , 一 半 ( < ) 中 位 数 。 即 ( ≥ ) 中 位 数 > ( < ) 中 位 数 的 数 。 所以不管奇偶,都会有一半(\ge)中位数,一半(<)中位数。即(\ge)中位数>(<)中位数的数。 ()(<)()>(<)

e g : 1    2    3    4 。 eg:1\;2\;3 \;4。 eg:1234
3 个 ( ≥ ) 2 , 1 个 ( < ) 2 , 则 2 一 定 是 中 位 数 , 2 个 ( ≥ ) 3 , 2 个 ( < ) 3 , 则 3 不 是 中 位 数 。 3个(\ge)2,1个(<)2,则2一定是中位数,2个(\ge)3,2个(<)3,则3不是中位数。 3()21(<)222()32(<)33

所 以 我 们 可 以 O ( n ) 判 断 一 个 数 字 是 不 是 中 位 数 。 所以我们可以O(n)判断一个数字是不是中位数。 O(n)

首 先 要 获 取 这 个 中 位 数 , 也 就 是 答 案 , 那 么 就 二 分 获 取 答 案 ! 首先要获取这个中位数,也就是答案,那么就二分获取答案!

我 们 二 分 获 取 x 之 后 , 判 断 该 数 字 是 不 是 可 以 为 中 位 数 , 如 果 是 l = m i d , 否 则 r = m i d − 1 。 我们二分获取x之后,判断该数字是不是可以为中位数,如果是l=mid,否则r=mid-1。 xl=midr=mid1

对 于 怎 么 O ( n ) 判 断 , 用 一 个 前 缀 和 数 字 存 取 与 x 大 小 有 关 的 。 对于怎么O(n)判断,用一个前缀和数字存取与x大小有关的。 O(n)x
i f ( a [ i ] > = x )    s u m [ i ] = s u m [ i − 1 ] + 1 if(a[i]>=x) \;sum[i] = sum[i-1]+1 if(a[i]>=x)sum[i]=sum[i1]+1
e l s e    s u m [ i ] = s u m [ i − 1 ] − 1 else\;sum[i]=sum[i-1]-1 elsesum[i]=sum[i1]1

当 处 理 完 前 缀 和 之 后 , 从 第 k 个 开 始 检 查 , 有 没 有 在 一 个 区 间 里 起 点 到 终 点 , ( ≥ x ) 的 数 是 否 大 于 ( < x ) 。 当处理完前缀和之后,从第k个开始检查,有没有在一个区间里起点到终点,(\ge x)的数是否大于(<x)。 k(x)(<x)
存 在 , 直 接 返 回 t r u e , 否 则 返 回 f a l s e 。 存在,直接返回true,否则返回false。 truefalse

Code(78MS)

#include "bits/stdc++.h"
using namespace std;

const int N = 2e5 + 10;
vector<int> a(N + 1), sum(N + 1);
int n, k;

bool check(int x) {
    for(int i = 1;i <= n; i++) sum[i] = sum[i - 1] + (a[i] >= x ? 1 : -1);
    int mx = 0, ans = sum[k];
    if(ans > 0) return 1;
    for(int i = k + 1;i <= n; i++) {
        mx = min(mx, sum[i - k]); // 终点
        ans = max(ans, sum[i] - mx); // 起点
        if(ans > 0) return 1;
    }
    return 0;
}

void solve() {
    cin >> n >> k;
    for(int i = 1;i <= n; i++) cin >> a[i];
    int l = 0, r = n + 1;
    while(l + 1 < r) {
        int mid = (l + r) / 2;
        if(check(mid)) l = mid;
        else r = mid - 1;
    }
    cout << (check(l + 1) ? l + 1 : l) << endl;
}

signed main() {
    solve();
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值