hdoj 6231 K-th Number

14 篇文章 0 订阅
6 篇文章 0 订阅

题目链接:K-th Number

题目大意:给你一个长度为n的数字,然后需要你找出这个序列里面长度大于等于k的所有子序列里第k小的数,然后扔到另一个数组里面去,然后寻找另一个数组里面第m大的数,问这个数

题目思路:我们可以将问题转化一下:我们需要去二分一个最大的x,且这个x满足有大于等于m个区间的第k小大于等于x(这样的话就满足了这个枚举的数要比我们最后要得到的数要大)。所以关键在于,如何求有多少个区间的第k小大于等于x。一个区间第k小要大于等于x,则这个区间至少要有k个数大于等于x我们枚举区间的左端点L。对于每个左端L,可以找一个最小的r使得,当右端点大于等于r时,[L,r]有k个数大于等于x。所以L为左端点的区间中满足要求的区间数有 n-r+1个,而这个r关于l显然是有单调性的,所以可以考虑用双指针O(n)求出所有r。

时间复杂度&&空间复杂度:O(nlogn)&&O(n)


#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long ll;
const ll maxn = 1e6+10;

ll a[maxn],b[maxn];
ll T,n,k,m;

bool check(ll mid){
    ll ans = 0,num = 0;
    ll l = 0,r = -1;
    while(r < n){
        if(num < k){
            if(a[r+1] >= mid) num++;
            r++;
        }else{
            if(num == k) ans += (n-r);
            if(a[l] >= mid) num--;
            l++;
            if(ans >= m) return true;//超过m个区间的第k小大于等于mid
        }
    }
    return false;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值