题意:给一个长度为n的序列,对于一个区间长度不小于k的子区间,中位数为这个区间排序后的第(k+1)/2个数字。现在求所有的长度不小于k的子区间,中位数的最大值是多少。
思路:首先要想到,对于一个中位数,在这题中,对于偶数长度,取的中位数是靠左边的那个,那么大于等于中位数的就有一半以上。
所以大于等于中位数的个数要比小于中位数的个数多。
利用这点,那么其实我们可以在On复杂度判断出来一个数字是不是 ≤中位数。
可以判断一个数是不是≤中位数?
那么我们是不是可以去二分?
其实这是有单调性的。
判断一个数字是不是≤中位数,只需要大于等于这个数字的个数 > 小于这个数字的个数即可
那么如果一个数字满足这个条件了。比他小也一定满足。
所以当一个数字满足,我们尝试增大这个数字看他是不是满足。
二分答案。
check的话,对于>=mid的值,我们把它记为1,<mid的值记为-1,处理一个前缀和。
然后只需要判断是不是存在区间长度≥k的区间和为正数即可。
只需要维护一个前缀和的前缀最小值,然后枚举当前为区间终点,前缀最小值的位置为起点即可。
#include<bits/stdc++.h>
using namespace std;
const int N=3e5;
int a[N],sum[N];
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 mi=~0u>>1,ma=0;
for(int i=k;i<=n;i++){
mi=min(mi,sum[i-k]);
ma=max(ma,sum[i]-mi);
}
return ma>0;
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int l=0,r=1e9;
while(l+1<r){
int mid=l+r>>1;
if(check(mid)) l=mid;
else r=mid;
}
cout<<l;
return 0;
}