K-th Number HDU - 6231 (二分+尺取)(好题)

该博客介绍了如何利用二分查找和尺取法解决ACM题目HDU - 6231(K-th Number)。题目要求在给定数组A中找到满足特定条件的B数组的第M大元素。博主分享了思路和AC代码,解释了如何通过二分确定位置并维护区间大小来减少复杂度,确保每个元素最多被遍历两次。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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(1N105),K(1KN),M. The second line contains N numbers Ai(1Ai109)
.

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
.
Sample Input
2
5 3 2
2 3 1 5 4
3 3 1
5 8 2
Sample Output
3
2
题意:懒得说了思路:这题最大的难点就是想到二分了,为什么可以想到二分呢,因为对于把数组里的数,我们显然可以通过二分确定位置,但是如果把b数组直接表示出来,显然是不能的,
但是分析发现,如果我们通过二分去确定位置,我们只用知道比当前数大的数有多少个,那么我们在分析可以知道,只要当某个区间的第k大的数大于等于当前二分的数,
剩下包含这个区间的区间都不用考虑了,如果小于的话只用吧终点往后移动,所以每一个数最多遍历两次,当然就是尺取了,那么怎么知道当前区间的第k大呢,一开始我都想用主席树了,但是其实不用我们只用维护当前区间大于等于x的个数就行了
ac代码:
#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
#define INFLL 0x3f3f3f3f3f3f3f
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int maxn = 1e5+50;
int n,k;
int a[maxn];
LL m;
int T;
int b[maxn];
int check(int x)
{
    int l = 1;
    int r = 1;
    LL sum1 = 0;//xiaoyudengyu
    LL sum2 = 0;//dayu
    int nowk;
    int cnt = 0;
    if(a[l]>=x){
        cnt++;
    }
    while(l<=r&&r<=n){
        if(r-l+1>=k){
           // cout<<"nowk: "<<nowk<<' '<<l<<' '<<r<<endl;
            if(cnt>=k){
                sum1+=(n-r+1);
                if(a[l]>=x){
                    cnt--;
                }
                l++;
            }
            else{
                r++;
                if(r>n){
                    break;
                }
                if(a[r]>=x){
                    cnt++;
                }
            }
        }
        if(r-l+1<k){
            r++;
             if(a[r]>=x){
                    cnt++;
                }
        }
    }
    //cout<<x<<' '<<sum1<<endl;
    if(sum1>=m){
        return 1;
    }
    else{
        return 0;
    }
}
int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%lld",&n,&k,&m);
        for(int i = 1;i<=n;i++){
            scanf("%d",&a[i]);
            b[i] = a[i];
        }
       // build(1,1,n);
        sort(b+1,b+n+1);
        int l = 0;
        int r = n+1;
        int mid;
        while(r>l+1){
            mid = (l+r)/2;
            if(check(b[mid])){
                l = mid;
            }
            else{
                r = mid;
            }
        }

       // cout<<r<<endl;
        printf("%d\n",b[l]);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值