HDU 6231 K-th Number
对于长度大于等于k的区间,取出第k大的数放置到新序列中。
问新序列中第m大的值是多少
那么题设可以转为 设答案的值为x
要使得答案成立 , 那么新序列中应该有m个值比x大
也就是 有大于等于m个区间能输出比x大的值
那么这些个区间 都应该包含了 大于等于k个 大于等于x 的数
二分找到刚好让x成为第m大的情况,满足单调性的,x越大,那么比x大的值就越少
使用二分套二分实现
内部的二分 , 枚举区间左端点 ,二分右端点刚好有k个的情况,然后加上可用的右端点
nlognlogn
#include<bitsdc++.h> #define ll long long #define int long long using namespace std; const ll mod=998244353; const int N=1e5+10; int a[N]; int n,k,m; int sum[N]; int jj(int l,int r){ if(r-l+1<k) return 0;//长度 if(sum[r]-sum[l-1]>=k)return 1;//个数 return 0; } int check(int p){ int num=p; for(int i=1;i<=n;i++){ sum[i]=sum[i-1]; if(a[i]>=num)sum[i]++; } int ans = 0; for(int l=1;l<=n;++l){ //cout<<"l== "<<l<<"\n"; int L=0,R=n+1; while(L<R){ int mid = L+R>>1; if(jj(l,mid)) R=mid; else L=mid+1; } if(L<1||L>n) continue;//右端不存在 int r = L; //cout<<"r =" <<r<<"\n"; ans = ans + (n-r+1); if(ans>=m)return 1; } return 0; } signed main(){ int t; cin>>t; while(t--){ scanf("%lld%lld%lld",&n,&k,&m); for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); } int l=1,r=1e9; while(l<r){ int mid=(l+r+1)/2; if(check(mid))l=mid; else r=mid-1; } cout<<l<<endl; } }