原题:
求f(x)不好求,那么可以尝试求f(x>=m)
求x为第k大出现了几次不好求,那么可以尝试求大于等于x的所有数作为第k大出现了几次
那么可以二分x,然后把所有大于等于x的视为1,其他视为0
问题转化为求有多少个区间,使得区间内1的个数>=k
区间问题可以枚举左端点,然后考虑右端点
显然右端点是递增的,所以不用二分,直接双指针扫一遍即可
本题本质在于用第一句话提到的方法,模糊掉不同的数,使得统计变得容易
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 #define LL long long 6 int n,a[110000],o; LL m; 7 int nx,nn; 8 //LL s[110000]; 9 LL cclt(int x){ 10 //for(int i=1;i<=n;++i) s[i]=s[i-1]+(a[i]>=x); 11 int j=0,bwl=0; LL cnt=0; 12 for(int i=1;i<=n;++i){ 13 bwl-=(a[i-1]>=x); 14 while(bwl<o && j<n) bwl+=(a[++j]>=x); 15 if(bwl<o) break; 16 cnt+=(n-j+1); 17 } 18 return cnt; 19 } 20 bool chck(int x){ 21 return cclt(x) >= m; 22 } 23 int bnrsch(){ 24 int l=nn,r=nx,md; 25 while(l+1<r){ 26 md=(l+r)>>1; 27 (chck(md) ? l : r)=md; 28 } 29 return chck(r) ? r : l; 30 } 31 void prvs(){ 32 nx=0,nn=1000000007; 33 } 34 int main(){ 35 int T; cin>>T; 36 while(T --> 0){ 37 scanf("%d%d%lld",&n,&o,&m); 38 prvs(); 39 for(int i=1;i<=n;++i){ 40 scanf("%d",&a[i]); 41 nx=max(nx,a[i]); 42 nn=min(nn,a[i]); 43 } 44 printf("%d ",bnrsch()); 45 } 46 return 0; 47 }