题目:http://codeforces.com/contest/1486/problem/D
题意:在长度为n的序列中,去不小于k的长度,然后排序,取它的中位数。
题解:二分枚举长度为中位数大小,然后check判断,check中大于等于这个中位数的置为1,小于这个中位数的置为-1,然后取前缀和,每一次减掉一个前面最小的前缀和,看看是否有某段大于这个中位数,有的话就返回1.
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 7;
int n, k;
int a[N], c[N], b[N];
int check(int mid)
{
for (int i = 1; i <= n; i++) //大于这个中位数置为1
{
if (a[i] >= c[mid])b[i] = 1;
else b[i] = -1;
}
int minn = 0, s_up = 0, s = 0; //minn代表前面最小的那个前缀
int flag = 0; //s代表前缀和
//s_up也代表前缀和,代表现有长度不小于k的情况下,前面的前缀和
for (int i = 1; i <= k - 1; i++)s += b[i];
for (int i = k; i <= n; i++)
{
s += b[i]; //每次加上一个
if (s - minn > 0) //判断减去前面最小的前缀和是否大于0
{
flag = 1;
break;
}
s_up += b[i - k + 1];
minn = min(minn, s_up);
}
return flag;
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++)scanf("%d", &a[i]), c[i] = a[i];
sort(c + 1, c + 1 + n); //将序列重新排序,用于二分中的check
int l = 1, r = n;
while (l < r)
{
int mid = (l + r + 1) / 2;
if (check(mid))l = mid;
else r = mid - 1;
}
printf("%d\n", c[l]);
return 0;
}