[每日一题]: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

posted @ 2020-04-21 19:14  IceSwords  阅读(216)  评论(0编辑  收藏  举报