Live2D

牛客网NOIP赛前集训营-提高组18/9/9 A-中位数

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

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小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的子区间中,中位数最大可以是多少。

输入描述:

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

输出描述:

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

输入

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

输出

复制
  1. 8684

备注:

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

思路:

表示考场上一看到这道题就一脸懵逼

于是交了一发主席树(当然不是正解)

听完讲评才发现二分水过。。。

其实很简单

先输进来

然后开个新数组去重,从小到大排序

然后就可以二分了

我们每次二分出一个答案

判断一下

怎么判断呢?

我们先O(n)扫一遍

x[i]大于等于这个答案话,就赋值为1

否则为-1

然后跑前缀和

再从len开始枚举

在枚举时维护一个最小前缀和(当前位置的前缀和-最小前缀和=最大前缀和)

如果最大前缀和>0,就是满足的(看题,这就说明它可以是从小到大第k/2位)

反之就不满足

OK

代码:

复制代码
  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #define rii register int i
  6. #define rij register int j
  7. using namespace std;
  8. int qzh[100005],x[100005],y[100005],z[100005],n,len;
  9. bool check(int bh)
  10. {
  11. int ltt=z[bh];
  12. int minx=192690817;
  13. memset(qzh,0,sizeof(qzh));
  14. for(rii=1;i<=n;i++)
  15. {
  16. if(x[i]>=ltt)
  17. {
  18. qzh[i]=1;
  19. }
  20. if(x[i]<ltt)
  21. {
  22. qzh[i]=-1;
  23. }
  24. if(i>=len)
  25. {
  26. minx=min(minx,qzh[i-len]);
  27. }
  28. qzh[i]+=qzh[i-1];
  29. if(i>=len)
  30. {
  31. if(qzh[i]-minx>0)
  32. {
  33. return 1;
  34. }
  35. }
  36. }
  37. return 0;
  38. }
  39. int main()
  40. {
  41. cin>>n>>len;
  42. for(rii=1;i<=n;i++)
  43. {
  44. scanf("%d",&x[i]);
  45. y[i]=x[i];
  46. }
  47. sort(y+1,y+n+1);
  48. int pre=0;
  49. for(rii=1;i<=n;i++)
  50. {
  51. if(y[i]==z[pre])
  52. {
  53. continue;
  54. }
  55. pre++;
  56. z[pre]=y[i];
  57. }
  58. // for(rii=1;i<=pre;i++)
  59. // {
  60. // cout<<z[i]<<" ";
  61. // }
  62. int l=1,r=pre;
  63. while(l!=r)
  64. {
  65. if(r-l==1)
  66. {
  67. if(check(r)==1)
  68. {
  69. l=r;
  70. }
  71. else
  72. {
  73. r=l;
  74. }
  75. break;
  76. }
  77. int mid=(l+r)/2;
  78. if(check(mid)==1)
  79. {
  80. l=mid;
  81. }
  82. else
  83. {
  84. r=mid;
  85. }
  86. }
  87. cout<<z[r];
  88. }
复制代码

 

posted @   ztz11  阅读(178)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示