zoukankan      html  css  js  c++  java
  • 【2017中国大学生程序设计竞赛-哈尔滨站】B

    原题:

    题意:

    给你一个长度为N的正整数组A,对于这个数组的所有子区间,若长度小于k则不管它,若长度大于等于k则取第k大放入数组B

    问你B中第M大的数是谁

    一眼序列分治,然而没思路

    数据结构?能想到从大到小排序,然后小于第i个数的都视为1,用数据结构维护第i个数在多少个区间是第k大

    然后就没有然后了……

    序列分治和数据结构自闭了两个小时,最后才想起来试试别的思路

    比如DP或二分什么的

    终于灵稽一动

    答案满足二分单调性

    二分的答案m越大,[m+1,n]中的数作为第k大的区间的总数量就越大

    那么二分一个答案m,问题转化为求[m+1,n]中的数作为第k大的区间的总数量

    因为只需要[m+1,n]中的任意一个数作为第k大,而[1,m]的数没有任何用,可以无视

    那么可以把大于m的数看成1,小于等于m的数k看成0

    问题转化为统计有多少个子区间,使得区间内有k个1

    只需要O(n)复杂度,可以双指针,左边指针i每次加1,如果经过1就让区间中1的减1,如果1的个数小于k,就让右边的指针j往右跑到刚好等于k为止,把n-j+1统计到结果即可

    注意二分的写法,容易写错

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 #define LL long long
     8 int rd(){int z=0,mk=1;  char ch=getchar();
     9     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
    10     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
    11     return z*mk;
    12 }
    13 int n,o;  LL m;
    14 int a[110000];
    15 int b[110000];
    16 LL cclt(int x){
    17     for(int i=1;i<=n;++i)  b[i]=(a[i]>=x);
    18     LL bwl=0;
    19     for(int i=1,j=0,k=0;i<=n && j<=n;++i){
    20         for(;k!=o && j<n;)  k+=b[++j];
    21         if(j>n || (j==n && k!=o))  break;
    22         bwl+=n-j+1;
    23         k-=b[i];
    24     }
    25     return bwl;
    26 }
    27 int bnrsch(int x,int y){
    28     int l=x,r=y,md;
    29     while(l+1<r){
    30         md=(l+r)>>1;
    31         (cclt(md)>=m ? l : r)=md;
    32     }
    33     return cclt(r)>=m ? r : l;
    34 }
    35 int main(){
    36     //freopen("ddd.in","r",stdin);
    37     int T;  cin>>T;
    38     while(T --> 0){
    39         cin>>n>>o>>m;
    40         int mx=0,mn=1000000007;
    41         for(int i=1;i<=n;++i){
    42             a[i]=rd();
    43             mx=max(mx,a[i]);
    44             mn=min(mn,a[i]);
    45         }
    46         printf("%d
    ",bnrsch(mn,mx));
    47     }
    48     return 0;
    49 }
    View Code
  • 相关阅读:
    内存分配小问题
    从MACHINE_START开始
    Linux驱动学习(二)
    9,斐波那契数列 6,旋转数组找最小 8青蛙跳台阶 JAVA实现
    数组练习题
    类的练习
    for循环练习题
    封装练习题
    Facebook成为Apache基金会的白金赞助商
    Visual Studio 2010
  • 原文地址:https://www.cnblogs.com/cdcq/p/11674434.html
Copyright © 2011-2022 走看看