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、付费专栏及课程。

余额充值