zoukankan      html  css  js  c++  java
  • 51nod 1685 第K大区间2

    定义一个长度为奇数的区间的值为其所包含的的元素的中位数。中位数_百度百科 

    现给出n个数,求将所有长度为奇数的区间的值排序后,第K大的值为多少。

     

    样例解释:


    [l,r]表示区间的值
    [1]:3
    [2]:1
    [3]:2
    [4]:4
    [1,3]:2
    [2,4]:2


    第三大是2

    Input
    第一行两个数n和k(1<=n<=100000,k<=奇数区间的数量)
    第二行n个数,0<=每个数<2^31
    Output
    一个数表示答案。
    Input示例
    4 3
    3 1 2 4
    Output示例
    2
    题目大意:定义一段奇数长度区间的值为其中位数,求所有子区间的值的第k大。

    题解:二分答案
    如果二分第k大为t,寻找大于t的区间的个数。设s[i]为1--i大于t的数的个数。
    如果一个区间的中位数大于t,那么
    s[r]-s[l-1]>(r-l+1)/2,整理一下
    2*s[r]-r>2*s[l-1]-(l-1),
    用树状数组统计一下即可。
    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define LL long long
    #define maxn 100009
    using namespace std;
    
    int n,l,r,mid,ans,a[maxn],b[maxn],tree[maxn*3][3];
    LL k;
    
    void add(int pos,int p){
        if(pos<=0)return;
        for(;pos<=maxn*3;pos+=pos&(-pos))tree[pos][p]++;
    }
    
    LL getsum(int pos,int p){
        LL all=0;if(pos<=0)return 0;
        for(;pos;pos-=pos&(-pos))all+=tree[pos][p];
        return all;
    }
    
    bool check(int p){
        LL s=0;
        memset(tree,0,sizeof(tree));
        for(int i=1;i<=n;i++)b[i]=a[i]>=p?1:0,b[i]+=b[i-1];
        for(int i=1;i<=n;i++)b[i]=2*b[i]-i+n;
        add(n,0);//???
        for(int i=1;i<=n;i++){
            s+=getsum(b[i],(i&1)^1);
            add(b[i],(i&1));
        }
        return s>=k;
    }
    
    int main(){
        scanf("%d%lld",&n,&k);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),r=max(r,a[i]);
        while(l<=r){
            mid=(l+r)>>1;
            if(check(mid))ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    AC
    
    
     
  • 相关阅读:
    公钥基础设施PKI 简介
    密码库LibTomcrypt的内容介绍及分析
    trace
    winform(C#)拖拽实现获得文件路径
    无线网络技术
    设备控制选项的部分列表
    dll #pragma data_seg注意事项
    RFC
    奥运火炬传递路线
    WMIC命令大全
  • 原文地址:https://www.cnblogs.com/zzyh/p/7650477.html
Copyright © 2011-2022 走看看