HDU 6231(二分&双指针)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6231(二分&双指针)相关的知识,希望对你有一定的参考价值。

HDU 6231(二分&双指针)

分为几个步骤:

1.二分枚举答案

2.对于每个枚举的答案 x x x找到有多少个区间的第 k k k ≥ x \\ge x x

瓶颈之处在于步骤2.

我们需要在 O ( n ) O(n) O(n)内求出来。

若一个区间的第 k k k ≥ x \\ge x x,则说明至少有 k k k个数 ≥ x \\ge x x

考虑双指针。

枚举 l l l,然后找到刚好出现 k k k个数 ≥ x \\ge x x的位置 r r r,然后此位置 l l l的答案是: n − r + 1 n-r+1 nr+1

显然当 l l l递增时, r r r是非递减的。

所以双指针是正确的。

总的时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

// Problem: B - K-th Number
// Contest: Virtual Judge - 2017CCPC 哈尔滨 [Cloned]
// URL: https://vjudge.net/contest/435963#problem/B
// Memory Limit: 262 MB
// Time Limit: 1000 ms
// Date: 2021-05-04 23:47:41
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=1e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
int a[N];
int n,k;
ll m;
bool ck(int x){
	int c=0,r=1;
	ll s=0;
	for(int l=1;l<=n;l++){
		while(r<=n&&c<k){
			if(a[r]>=x) c++;
			r++;
		}
		if(c==k) s+=n-r+2;
		if(a[l]>=x) c--; 
	}
	return s>=m;
}
int main(){
	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=0,r=1e9,ans;
		while(l<=r){
			int mid=l+r>>1;
			if(ck(mid)) l=mid+1,ans=mid;
			else r=mid-1;
		}
		printf("%d\\n",ans);
	}
	return 0;
}

以上是关于HDU 6231(二分&双指针)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 6231 (二分+双指针)

hdu-6231 二分

hdu 6231 -- K-th Number(二分+尺取)

HDU - 6231:K-th Number (不错的二分)

HDU - 6231 K-th Number (2017CCPC哈尔滨站 二分+尺取法)

百度之星2017 HDU 6119 小小粉丝度度熊 二分+双指针