HDU 6231 K-th Number

对于长度大于等于k的区间,取出第k大的数放置到新序列中。

问新序列中第m大的值是多少

 

那么题设可以转为 设答案的值为x

要使得答案成立 , 那么新序列中应该有m个值比x大

也就是  有大于等于m个区间能输出比x大的值

那么这些个区间 都应该包含了 大于等于k个  大于等于x 的数

二分找到刚好让x成为第m大的情况,满足单调性的,x越大,那么比x大的值就越少

使用二分套二分实现

内部的二分 , 枚举区间左端点 ,二分右端点刚好有k个的情况,然后加上可用的右端点

nlognlogn

#include<bitsdc++.h>
#define ll long long
#define int long long
using namespace std;
const ll mod=998244353;
const int N=1e5+10;
int a[N];    
int n,k,m;
int sum[N];
int jj(int l,int r){
    if(r-l+1<k)    return 0;//长度 
    if(sum[r]-sum[l-1]>=k)return 1;//个数 
    return 0;
}
int check(int p){
    int num=p;
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1];
        if(a[i]>=num)sum[i]++;
    }
    int ans = 0;
    for(int l=1;l<=n;++l){
        //cout<<"l==  "<<l<<"\n";
        int L=0,R=n+1;
        while(L<R){
            int mid = L+R>>1;
            if(jj(l,mid))    R=mid;
            else        L=mid+1;
        }
        if(L<1||L>n)    continue;//右端不存在 
        int r = L;
        //cout<<"r =" <<r<<"\n";
        ans = ans + (n-r+1);
        if(ans>=m)return 1;
    }
    return 0;
}
signed main(){
    int t;
    cin>>t;
    while(t--){
        scanf("%lld%lld%lld",&n,&k,&m);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        int l=1,r=1e9;
        while(l<r){
            int mid=(l+r+1)/2;
            if(check(mid))l=mid;
            else r=mid-1;
        }
        cout<<l<<endl; 
    } 
}

 

posted @ 2021-11-10 22:51  PdrEam  阅读(19)  评论(0编辑  收藏  举报