牛客noip前集训营(第一场)提高T1

链接:https://www.nowcoder.com/acm/contest/172/A
来源:牛客网

题目描述

小N得到了一个非常神奇的序列A。这个序列长度为N,下标从1开始。A的一个子区间对应一个序列,可以由数对[l,r]表示,代表A[l], A[l + 1], ..., A[r]这段数。对于一个序列B[1], B[2], ..., B[k],定义B的中位数如下:
1. 先对B排序。得到新的序列C。
2. 假如k是奇数,那么中位数为。假如k为偶数,中位数为
对于A的所有的子区间,小N可以知道它们对应的中位数。现在小N想知道,所有长度>=Len的子区间中,中位数最大可以是多少。

输入描述:

第一行输入两个数N,Len。
第二行输入序列A,第i个数代表A[i]。

输出描述:

一行一个整数,代表所有长度>=Len的子区间中,最大的中位数。
示例1

输入

复制
11 3
4864 8684 9511 8557 1122 1234 953 9819 101 1137 1759 

输出

复制
8684

备注:

数据范围:
30%: n <= 200
60%: n <= 2000
另外有20%:不超过50个不同的数
100%:1<=Len<=n<=10^5, 1 <= a[i] <= 10^9

题目要求求区间最大中位数。

最暴力的方法就是枚举每一个区间,然后将区间排序,查询中位数。

稍微有话一下上边做法,就维护一个单调序列,查询中位数。

然后看到网上还有一种做法,查询中位数当做查询区间第k大的数,用到了什么叫划分树的东西,枚举区间然后查询,貌似是一有80分。

正解二分答案+前缀和:

既然要二分答案,就需要序列有序,那么另开一个数组,储存序列排序,用于二分。

那么对于每个二分的数,那么我们怎么来判断呢?

对于每个数字x,我们对于每个判断序列中有多少个比x大的数和比x小的数,为了方便判断,预处理一个数组C,原序列中的数大于等于x,C[i]=1,否则C[i]=-1;

我们判断这个数是不是中位数,那么就要让小于它的数和大于等于它的数数量相等。

循环判断,当现枚举的长度大于等于想要的长度时,找出左边最少有多少个比它小的数,往右找到比它大的数。

if(i>=len)ban=min(ban,c[i-len]);

我们每次前缀和,统计+1和-1的数量差。

c[i]+=c[i-1];

满足条件go on!!

if(i>=len&&c[i]-ban>0)return 1;

总的时间复杂度$O(nlongn)$

代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define LL long long
int read()
{
    int sum=0,fg=1; char c=getchar();
    while(c<'0'||c>'9'){ if(c=='-')fg=-1;c=getchar(); }
    while(c>='0'&&c<='9'){ sum=sum*10+c-'0';c=getchar(); }
    return sum*fg;
}
int n,len,a[100006],b[100006];
int c[100006],ban,ans;
bool check(int x)
{
    ban=1234567890;
    for(int i=1;i<=n;i++)
        if(a[i]>=x)c[i]=1; else c[i]=-1;
    bool flag=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==x)flag=1;
        if(i>=len)ban=min(ban,c[i-len]);
        c[i]+=c[i-1];
        if(i>=len&&c[i]-ban>0)return 1;
    }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&len);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
    sort(b+1,b+1+n);
    int l=n/2,r=n;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(check(b[mid]))ans=b[mid],l=mid+1;
        else r=mid-1;
    }
    printf("%d",ans);
}
原文地址:https://www.cnblogs.com/rmy020718/p/9614724.html