HDU - 6231_K-th Number

题面

Alice are given an array A[1…N] with N numbers.

Now Alice want to build an array B by a parameter K as following rules:

Initially, the array B is empty. Consider each interval in array A. If the length of this interval is less than K, then ignore this interval. Otherwise, find the K-th largest number in this interval and add this number into array B.

In fact Alice doesn’t care each element in the array B. She only wants to know the M-th largest element in the array B. Please help her to find this number.

input

The first line is the number of test cases.

For each test case, the first line contains three positive numbers N(1≤N≤105),K(1≤K≤N),M. The second line contains N numbers Ai(1≤Ai≤109).

It’s guaranteed that M is not greater than the length of the array B.

output

For each test case, output a single line containing the M-th largest element in the array B.

题意

  • 找出区间长度大于k的所有子区间的第k大,并将他们存入B数组里,输出B数组里的第m大

题解

  • 首先我们对于一个数x,如果以他为第k大的区间数和大于x的数作为第k大的区间数的总和大于m,那么答案肯定是比x还要大的,相反,如果总和小于m,那么答案肯定要更小,这样就存在二分性,我们可以二分求答案,难点是我们要怎么去算出上述的区间总和,其实很简单,我们可以用尺取法,首先考虑一下如果我们找到前缀刚好有k个大于等于x的,那么后面的所有数都可以代表一个满足区间,因为加了后面的数,区间肯定存在第k大,而且第k大等于x或者大于x,这样我们通过维护这个刚好第k大,就可以找出所有满足区间
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int maxn = 1e5+9;

int a[maxn];
int n,k;
ll m;

bool check(int x){
    ll ans=0;
    int num = 0;
    int j=1;
    for(int i = 1; i <= n; i++){
        if(a[i] >= x) num++;
        if(num == k){
            ans += (n-i+1);
            while(a[j] < x){
                ans += (n-i+1);
                j++;
            }
            num--;
            j++;
        }
    }
    return ans >= m;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%lld",&n,&k,&m);
        for(int i = 1; i <= n; i++){
            scanf("%d",&a[i]);
        }
        int l=1,r=1000000000;
        while(l<r){
            int mid = l+(r-l+1)/2;
            if(check(mid))l = mid;
            else r = mid-1;
        }
        printf("%d\n",l);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值