【HDOJ 6231】 k-th number 二分答案

链接

http://acm.hdu.edu.cn/showproblem.php?pid=6231

题意

给你一个数列a[1...n],对于a中的每个长度大于等于k的区间,把其中第k大的数加进数列b中,求数列b中第m大的数。

solution

二分答案的思想由来

如果任取一个数x作为答案,怎么判断它大了还是小了?如何调整?

  1. 对于任意一个区间,如果x在其中的排名>m,即比x大的数有至少m个,那么x就不能作为这个区间的结果。
  2. 如果x满足上述条件,要让x作为区间的结果,需要增大x的值;反之减小x的值。
  3. 随着x的值增大,在数列b中排名一定会上升。满足单调性

至此我们可以使用二分答案的做法:
二分答案x的数值大小,即b中排名<=k的( 区间中有至少k个数满足大于等于x 的 区间个数)数的大小。
如果区间个数>=m,表明至少有m个数排在x之前,更新答案,增大x;反之减小x。

code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100005;
const double pi = 3.14159265358979;
ll n,k,m;
int t;
int a[N];
int num[N]={0};

bool check(int mid){
	ll cnt=0;  //>=mid 的区间的个数 
	num[0]=0;
	for(int i=1;i<=n;i++) num[i]=num[i-1]+(a[i]>=mid);
	for(int l=1;l<=n;l++){
		int r=lower_bound(num+1,num+n+1,num[l-1]+k)-num;
		cnt+=(n-r+1);
	} 
	return cnt>=m; 
}

int main(){
	cin>>t;
	while(t--){
		cin>>n>>k>>m;
		int l=1e9,r=0,mid,ans;
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			r=max(a[i],r);
			l=min(l,a[i]);
		}
		while(l<=r){
			mid=(l+r)>>1;
			if(check(mid)) ans=mid,l=mid+1;   // >=mid 的数 >= M 个 
			else r=mid-1; 
		}
		printf("%d\n",ans);
	}
	return 0;
}
posted @   starlightlmy  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示