Codeforces Round #703 Div2 D. Max Median 二分答案
传送门: https://codeforces.com/contest/1486/problem/D
题意
给
一
个
长
度
为
n
的
数
组
,
在
里
面
找
若
干
个
长
度
≥
k
的
区
间
,
问
这
些
区
间
中
最
大
的
中
位
数
是
多
少
。
给一个长度为n的数组,在里面找若干个长度\ge k的区间,问这些区间中最大的中位数是多少。
给一个长度为n的数组,在里面找若干个长度≥k的区间,问这些区间中最大的中位数是多少。
中
位
数
,
请
输
出
最
大
值
。
\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个(≥)2,1个(<)2,则2一定是中位数,2个(≥)3,2个(<)3,则3不是中位数。
所 以 我 们 可 以 O ( n ) 判 断 一 个 数 字 是 不 是 中 位 数 。 所以我们可以O(n)判断一个数字是不是中位数。 所以我们可以O(n)判断一个数字是不是中位数。
首 先 要 获 取 这 个 中 位 数 , 也 就 是 答 案 , 那 么 就 二 分 获 取 答 案 ! 首先要获取这个中位数,也就是答案,那么就二分获取答案! 首先要获取这个中位数,也就是答案,那么就二分获取答案!
我 们 二 分 获 取 x 之 后 , 判 断 该 数 字 是 不 是 可 以 为 中 位 数 , 如 果 是 l = m i d , 否 则 r = m i d − 1 。 我们二分获取x之后,判断该数字是不是可以为中位数,如果是l=mid,否则r=mid-1。 我们二分获取x之后,判断该数字是不是可以为中位数,如果是l=mid,否则r=mid−1。
对
于
怎
么
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[i−1]+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[i−1]−1
当
处
理
完
前
缀
和
之
后
,
从
第
k
个
开
始
检
查
,
有
没
有
在
一
个
区
间
里
起
点
到
终
点
,
(
≥
x
)
的
数
是
否
大
于
(
<
x
)
。
当处理完前缀和之后,从第k个开始检查,有没有在一个区间里起点到终点,(\ge x)的数是否大于(<x)。
当处理完前缀和之后,从第k个开始检查,有没有在一个区间里起点到终点,(≥x)的数是否大于(<x)。
存
在
,
直
接
返
回
t
r
u
e
,
否
则
返
回
f
a
l
s
e
。
存在,直接返回true,否则返回false。
存在,直接返回true,否则返回false。
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();
}