K-th Number


突破口:直接考虑最后的B序列是一个由原序列中的数字多次或0次出现构成的序列,那么将B序列排序之后我们发现,对于每个数字出现的位置都有一个L,R,并且数字越小的其实排名越靠后,由这里我们就可以发现,最后的答案是满足二分性质的,所以我们可以直接二分Mst求出mid在B序列中的R即可.
这一部分可以用尺取法,即如果一个数要想对当前mid做出贡献,那么他所在的区间必须有>=k个比mid大的元素,所以将所有>=mid的元素看做一个,然后枚举右端点即可


#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ls rt<<1
#define rs rt<<1|1
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
#define yes puts("YES")
#define no puts("NO")
#define ios ios::sync_with_stdio(0);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef vector<int> VI;
const int maxn = 3e5 + 6;
const LL inf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
LL qp(LL x,LL y){LL ans=1;x%=mod;while(y){if(y&1) ans=ans*x%mod;x=x*x%mod;y>>=1;}return ans;}
LL inv(LL x){return qp(x,mod-2);}

//head
LL _,n,m,k,a[maxn],b[maxn];
bool ok(LL x){
    vector<LL>v;
    for(int i=1;i<=n;i++) if(b[i]>=x) v.pb(i);
    v.pb(n+1);
    int sz=v.size();
    LL ans=0;
    for(int i=0;i<=sz-k-1;i++){
        LL l=v[i],r=v[i+k]-v[i+k-1];
        ans+=l*r;
    }
    return ans>=m;
}

int main(){
    for(scanf("%lld",&_);_;_--){
        scanf("%lld%lld%lld",&n,&k,&m);
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]),b[i]=a[i];
        sort(a+1,a+1+n,greater<LL>());
        int l=1,r=n,ans=-1;
        while(l<=r){
            int mid=l+r>>1;
            if(ok(a[mid])) {r=mid-1;ans=mid;}
            else l=mid+1;
        }
        printf("%d\n",a[ans]);
    }

}