标签:pre 思考 偶数 pos return 是什么 out 利用 中位数
问题
C得到了一个非常神奇的序列A。这个序列长度为N,下标从1开始。A的一个
子区间对应一个序列,可以由数对[l,r]表示,代表A[l], A[l + 1], ..., A[r]这段数。
对于一个序列B[1], B[2], ..., B[k],定义B的中位数如下:
解:
网上找到的题目 觉得很好就记下来了
首先二分答案的题目满足的性质一定是单调性
不一定是最小值最大或者最大值最小
当我们对于答案没有思路的时候不妨逆向思考利用二分答案增加条件
此题便是如此
首先直接暴力似乎不可做 并且答案也不好求 这让我想起了CF上的一道题 也是求中位数并且利用了二分答案
正着不好思考 答案似乎太难求
假如二分答案的话 似乎大于的都可以标为1 小于的话都可以标为-1 因为数值并不产生影响我们只会关心大小关系 调大mid 显然合法的区间会变小 调大mid合法的区间会变大 满足单调性 我们考虑二分答案
那一个区间的合法条件是什么呢???
区间的和>0 代表存在一个序列 使得 中位数>mid 假如我们调大mid 存在性就会越来越小 换句话说我们只要逼近二分的答案 就能出解
code:
//
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxnn 200100
ll n,LEN;
ll a[maxnn];
ll b[maxnn];
ll sum[maxnn];
bool isok(ll mid)
{
ll pos=0,ans=1111111000000;
for(int i=1;i<=n;i++)
{
if(a[i]>=mid) b[i]=1;
else b[i]=-1;
}
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+b[i];
while(pos<=i-LEN)
{
ans=min(ans,sum[pos]);
pos++;
}
if(i>=LEN)
if(sum[i]-ans>0) return true;
}
return false;
}
int main()
{
scanf("%lld%lld",&n,&LEN);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
ll l=0,r=100000000000;
while(l<=r)
{
ll mid=(l+r)/2;
if(isok(mid))
{
l=mid+1;
}
else
{
r=mid-1;
}
}
cout<<r;
}
标签:pre 思考 偶数 pos return 是什么 out 利用 中位数
原文地址:https://www.cnblogs.com/OIEREDSION/p/11828047.html