K-th Number
题意:有一个数列a,在a的所有长度不小于k的连续子序列中,把其中的第k大数加入数列b,求数列b的第m大数;
思路:所求数一定是数列a中的数,那么就在a 中任选一个数x,若a的所有长度不小于k的连续子序列中第k大数不小于x的子序列一共有Q个,那么x在数列b中至少是第Q大数;若Q<m,说明x可能找小了;若Q>m,说明x找大了,这里就会发现可以二分查找x;
那么怎么判断x是第几大数呢?这里就用到了尺取法;
用尺取法来找数列a中有几个区间的第k大数大于等于x;
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
long long n, m, k;
long long a[maxn], b[maxn];
bool check(long long j, long long cnt, long long x){
if(a[j]>=x) cnt++;
return cnt<k;
}
bool cal(long long x){
long long cnt=0, num=0;
if(a[0]>=x) cnt++;
for(long long i=0, j=0; i<n; i++){
while(j+1<n&&check(j+1, cnt, x)){
j++;
if(a[j]>=x) cnt++;
}
num+=(n-j-1);
if(a[i]>=x) cnt--;
}
return num>=m;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d%d", &n, &k, &m);
for(long long i=0; i<n; i++){
scanf("%d", &a[i]);
b[i]=a[i];
}
sort(b, b+n);
long long l=0, r=n-1;
long long ans=0;
while(l<r){
int mid=(l+r)>>1;
if(cal(b[mid])){
l=mid+1;
ans=mid;
}
else{
r=mid-1;
}
}
printf("%lld\n", b[ans]);
}
return 0;
}