题目描述
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 fi nd this number.
输入描述:
The first line is the number of test cases. For each test case, the first line contains three positive numbers N(1≤N≤105);K(1≤K≤N);M.
The second line contains N numbers Ai(1≤Ai≤109).
It's guaranteed that M is not greater than the length of the array B.
输出描述:
For each test case, output a single line containing the M-th largest element in the array B.
示例1
输入
复制
2
5 3 2
2 3 1 5 4
3 3 1
5 8 2
输出
复制
3
2
这道题的题意就是给一个数组,求这个数组中所有长度大于等于k的区间中的所有第K大数组成集合中的第K大数
说实话我以为是分治,然后没有做出来,于是我开始看题解。
学到了一种比较巧妙的枚举区间的方法----尺取法
先来说说这道题怎么写:
对于答案x,必定存在大于等于k个区间的第K大数大于x,因此我们可以二分答案,二分出x的值,check()
函数才是关键
check
函数中我们令左右指针left
和right
同时指向一开始的起点,然后右指针开始向右扩展,每一扩展到一个大于x的数便累加到记录当前区间比x大的数的个数num
变量上。当num
的值正好等于k时,意味着这是一个第k大数大于等于x的区间,因此右指针继续不论怎么向右移动,都是合法区间。因此,记录区间个数的变量cnt
可以直接加上n-right+1
。这个时候再向右移动左区间直到当前区间里面的大于x的数小于num
,在此过程中,左区间每移动一次,贡献出的不同区间数也是n-right+1
.代码长这个样子:
for(LL left = 1,right = 1;right <= n;right ++){
if(a[right] >=x) num++;
if(num == k){
cnt += n - right + 1;
while(a[left] < x){
cnt += n - right + 1;
left ++ ;
}
left ++;
num --;
}
}
总的代码
LL T,n,m,k,a[N];
vector<int> ans;
bool check(int x){ //x为二分估计的答案值
LL cnt = 0; //第k大数大于等于x的区间个数
LL num = 0; //当前尺取的区间中大于等于x的数的个数
for(LL left = 1,right = 1;right <= n;right ++){
if(a[right] >=x) num++;
if(num == k){
cnt += n - right + 1;
while(a[left] < x){
cnt += n - right + 1;
left ++ ;
}
left ++;
num --;
}
}
if(cnt >= m) return 1;
return 0;
}
void solve(){
LL l = 1, r = 0x3f3f3f3f;
while(l<r){
LL mid = l+r >> 1;
if(check(mid)) l = mid+1;
else r = mid;
}
printf("%lld\n",l-1ll);
}
int main(){
T = read();
while(T--){
n = read(),k = read(),m = read();
rep(i,1,n) a[i] = read();
solve();
}
return 0;
}