[每日一题]:K-th Number
题目:
题目大意:
给一个数组,每隔 k 个间隔,从这 k 个数里面选 出 第 k 大,放到 B 数组中,
最后输出 B 数组中第 M 大的数。
考察点:
二分、尺取、逆向思维
分析:
Code:
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;
int a[maxn],copys[maxn];
LL t,n,m,k;
// 尺取
LL Check(int x) {
LL ans = 0,res = 0,j = 1;
for(int i = 1; i <= n; i ++) {
if(a[i] >= x) ans ++;
// 根据上文说的性质
if(ans == k) {
res += n - i + 1;
while(a[j] < x) {
res += n - i + 1;
j ++;
}
ans --;
j ++;
}
}
return res;
}
int main(void) {
scanf("%lld",&t);
while(t --) {
scanf("%lld%lld%lld",&n,&k,&m);
for(int i = 1; i <= n; i ++) {
scanf("%d",&a[i]);
copys[i] = a[i];
}
sort(copys + 1,copys + 1 + n);
LL l = 1,r = n;
while(l < r) {
LL mid = (l + r + 1) >> 1;
// 如果说区间个数较多,说明假设的值较小,可能有更合适的值
if(Check(copys[mid]) >= m) l = mid;
else r = mid - 1;
}
// 返回的是下标
printf("%lld\n",copys[l]);
}
return 0;
}
后记:
感谢师傅大佬的贴切讲解,万分感谢,解决了我在这道问题上的诸多疑问。
学到了一些什么东西呢?
首先,要二分必须是有序的,如果无法改变原数组,那么我们可以另开一个数组,
将其弄成有序的,进行二分。
计算区间个数,尺取真的是一把利器。
大佬链接:
https://blog.nowcoder.net/n/3a1dad4a9e4f4ac2993fa2d8e0e6c77f
如果说年轻人未来是一场盛宴的话,那么我首先要有赴宴的资格。