• 51 NOD 1685 第K大区间2 二分+BIT


    题目描述:

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

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

      样例解释:


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


      第三大是2

    输入:

      第一行两个数n和k(1<=n<=100000,k<=奇数区间的数量) 第二行n个数,0<=每个数<2^31

    输出:

      一个数表示答案。

    题解:

      二分答案t,统计中位数大于等于t的区间有多少个。

       设a[i]为前i个数中有a[i]个数>=t,若奇数区间[l,r]的中位数>=t,

      则(a[r]-a[l-1])*2>=r-l+1,即(a[r]*2-r)>=(a[l-1]*2-l+1)。

      b[i]=a[i]*2-i,

      这样题目就变成了统计 b[i]>=b[j] i与j奇偶性不同,BIT

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 2e6+20, M = 1e5+10, mod = 1e9+7, inf = 2e9;
    typedef long long ll;
    
    int C[N][2],n;
    int a[N],b[N];
    ll k;
    void update(int x,int p) {
        if(x==0) return ;
        for(int i=x;i<N;i+=i&(-i)) C[i][p]+=1;
    }
    int getsum(int x,int p) {
        int s = 0;
        for(int i=x;i;i-=i&(-i)) s+=C[i][p];
        return s;
    }
    ll ask(int t)
    {
        memset(C,0,sizeof(C));
        b[0]=0;
        for(int i=1;i<=n;i++) b[i]=a[i]>=t?1:0,b[i]+=b[i-1];
        for(int i=1;i<=n;i++) b[i] = b[i]*2-i+M;
        ll s=0;
        update(M,0);
        for(int i=1;i<=n;i++) {
            s+=getsum(b[i],(i&1)^1);
            update(b[i],(i&1));
        }
        return s;
    }
    int main(){
        scanf("%d%lld",&n,&k);
        int mx = 0;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]),mx = max(mx, a[i]);
        int l=0,r=mx,ans=0;
       // cout<<ask(2)<<endl;//return 0;
        while(l<=r) {
            int mid = (l+r)>>1;
            if(ask(mid)>=k) l=mid+1,ans=mid;
            else r=mid-1;
        }
        printf("%d
    ",ans);
    }
  • 相关阅读:
    eslint 的 env 配置是干嘛使的?
    cookie httpOnly 打勾
    如何定制 antd 的样式(theme)
    剑指 Offer 66. 构建乘积数组
    剑指 Offer 65. 不用加减乘除做加法
    剑指 Offer 62. 圆圈中最后剩下的数字
    剑指 Offer 61. 扑克牌中的顺子
    剑指 Offer 59
    剑指 Offer 58
    剑指 Offer 58
  • 原文地址:https://www.cnblogs.com/zxhl/p/5664723.html
Copyright © 2020-2023  润新知