HDU6231 K-th Number(技巧二分+尺取)

it2026-08-06  11

hdu6231

根本想不到啊…

题意

在所有区间长度大于 k k k的区间选出第 k k k大的数加入数组 b b b

问最后数组 b b b的第 m m m

做法

枚举区间计算复杂度上天

但是可以二分计算答案

二分 m i d mid mid,假设最后的答案大于等于 m i d mid mid就返回 t r u e true true

怎么 c h e c k ? check? check?

二分之后,每个数要么大于等于 m i d mid mid,要小于 m i d mid mid

我们想求有多少区间的第 k k k大比 m i d mid mid

维护 l , r l,r l,r指针尺取区间

如果 a i > = m i d a_i>=mid ai>=mid,计数器加一

当计数器到达 k k k时,说明包含当前区间的区间的第 k k k大一定大于等于 m i d mid mid

所以计算 a n s ans ans

这样通过尺取的手段,就得到了 a n s ans ans,也就是多少个区间的第 k k k大比 m i d mid mid还大

如果 a n s > = m ans>=m ans>=m,说明答案确实大于等于 m i d mid mid

否则,说明答案小于 m i d mid mid

#include <bits/stdc++.h> using namespace std; #define int long long const int maxn=2e5+10; int n,k,a[100009],m; bool isok(int x) { int ans=0,num=0,j=1; for(int i=1;i<=n;i++) { if( a[i]>=x ) num++; if( num==k )//说明区间第k大是大于x的 { ans+=n-i+1;//右端点的取值 while( a[j]<x )//移动左端点 ans+=n-i+1,j++; num--,j++; } } if( ans>=m ) return true; return false; } signed main() { int t; cin >> t; while( t-- ) { cin >> n >> k >> m; int l=1e9+1,r=0; for(int i=1;i<=n;i++) { cin >> a[i]; l = min(l,a[i]); r = max(r,a[i]); } int ans=0; while( r>=l ) { int mid = l+r>>1; if( isok(mid) ) l=mid+1,ans=mid; else r=mid-1; } cout << ans << '\n'; } }
最新回复(0)