cdcq

梦幻小鱼干

导航

【CCPC2017哈尔滨B】K-th Number

原题:

 

 

求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\n",bnrsch());
45     }
46     return 0;
47 }
View Code

 

posted on 2020-06-15 18:24  cdcq  阅读(195)  评论(0编辑  收藏  举报