HDU 6231 --- K-th Number(二分+尺取+思维)

K-th Number

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 945    Accepted Submission(s): 357


Problem Description
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 find this number.
 

Input
The first line is the number of test cases.

For each test case, the first line contains three positive numbers N(1N105),K(1KN),M. The second line contains N numbers Ai(1Ai109).

It's guaranteed that M is not greater than the length of the array B.
 

Output
For each test case, output a single line containing the M-th largest element in the array B.
 

Sample Input
 
 
2 5 3 2 2 3 1 5 4 3 3 1 5 8 2
 

Sample Output
 
 
3 2
 

Source
 

Recommend
jiangzijing2015   |   We have carefully selected several similar problems for you:   6297  6296  6295  6294  6293
/**
题意:给定一个长度为n的序列a[i],问a序列的所有子序列(连续子区间)的第k大的数组成的数组b的第m大的数;
懵圈了 后来仔细想了一下 是可以二分的;
解题思路:二分x 尺取法找出第k大数大于等于x的连续区间的个数num;
看num和m的关系  若num>m 则说明二分出的x比较小(区间个数过多) 因此需要二分x加大 右移 也就是 l = mid+1; 
若num<m 说明二分出的x比较大 因此需要缩小x 左移 r=mid; 总的来说就是  确定区间的数量和m的关系 来确定二分的走位
求解大于等于k区间的个数 :尺取法
****tricks***
二分角标确定(最大值最小化,最小值最大化均可) 读题 

*/

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<cstring>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;

const int maxn=1e5+7;
int n,k,a[maxn];
ll m;

bool judge(int x){
	int l=1,num=0;
	ll ans=0;
	for(int i=1;i<=n;i++) {
		if(x<=a[i]) num++;
		if(num==k){
			ans+=n-i+1;
			while(x>a[l]){
				ans+=n-i+1;
				l++;
			}
			num--;
			l++;
		}
	}
	return (ans>=m);
}

void solved(){
	int t;scanf("%d",&t);
	while(t--){
		scanf("%d %d %lld",&n,&k,&m);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		int l=1,r=1e9+7;
		while(l<r){
			int mid=(l+r)/2;
			if(judge(mid)) l=mid+1;
			else r=mid;
		}
		printf("%d\n",l-1);
	}
}

int main (){
	solved();
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值