1. 程式人生 > 其它 >HDU 6231 K-th Number

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; } }