K-th Number ---newcoder【自己的理解】

题意:
在给定的数组中找出所有区间的第k大的数 全部放入另一个数组中 然后求另一个数组中的第M大
思路:
用二分的check(mid) //这里是一个二分模板之一;
思路:
因为要在给定的数组中找出所有区间第k大的数,并且全部放入另一个数组之后要第M大, 我们就假设 mid 就是那个第m大的值,那么一定有m-1个值mid 大,所以我们的check(mid) 就是检查是否有m-1个值比mid大, 这里二分思想,如果有那么应该取mid - r 之间否则取l - mid 之间!
具体check(mid)如何检查第k大的数大于mid 的区间的个数!
这里用到了尺取:

ll check(ll x)
{
 ll ans = 0; //区间的个数
 ll l = 1, r = 0;
 ll pre = 0; //用于记录数字大于x的个数
 while(l <= n) //从开始枚举每一个数字
 {
  while(r < n && pre < k)//如果这个数字大于x并且现在大于x的数个数还小于k个
  {
   if(a[++r] >= x)
   pre ++; //那么大于x个数加一
  }
  if(pre == k)//如果大于x个数正好等于k 我们就可以得到从第r到第n个数字和后面的每个数字组成的区间都一定大于m个
  //这里比较难理解 好好想想 或者自己拿个数组试试
  {
   ans += n-r+1;
  }
  if(a[l] >= x) //如果尺取里面最后的数字如果大于x 由于尺取要向前 就要减去这个数字
  {
   pre --; //减去这个数字
   l ++; 
  }
  else
  l ++;
 }
 return ans;
}

第k大的数大于x的区间的数量求法:
满足条件的数组中,至少应该有k个数大于x,那枚举区间左界L时,我们可以直接从L出发向右扫描看看有多少大于x的数,当大于x的数正好满足k个时,将这个位置记为R,在当前位置R再往右扫描,大于x的数只会比k多不会比k少,也就是R之后的数与其组成连续区间的话都是符合条件的(此处有n-R+1个)。那我们将L向右移动,R也必须向右移动,才能保准k的数量。
每次二分一个x,都经过上述过程
二分+尺取 复杂度是O(nlogn)
————————————————
这一小部分是转载的 可以看一下喽
原文链接:https://blog.csdn.net/qq_35975367/article/details/105801810

具体代码看下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 1e10;
const int maxn = 1e6+6;
ll a[maxn];
ll n, k, m;
ll check(ll x)
{
 ll ans = 0;
 ll l = 1, r = 0;
 ll pre = 0;
 while(l <= n)
 {
  while(r < n && pre < k)
  {
   if(a[++r] >= x)
   pre ++;
  }
  if(pre == k)
  {
   ans += n-r+1;
  }
  if(a[l] >= x)
  {
   pre --;
   l ++;
  }
  else
  l ++;
 }
 return ans;
}

int main()
{
 int t;
 scanf("%d",&t);
 while(t --)
 {
  scanf("%d%d%d",&n,&k,&m);
  for(int i = 1; i <= n; i ++)
  {
   scanf("%lld",&a[i]);
  }
  ll l = 1;
  ll r = inf;
  while(l+1 < r)
  {
   ll mid = (l+r) >> 1;
   if(check(mid) >= m)
   {
    l = mid;
   }
   else
   {
    r = mid;
   }
  }
  printf("%lld\n",l);
 }
 return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值