[CQOI]中位数 && 中位数(qbxt) && 众数(qbxt)

给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。

输入输出格式

输入格式:

第一行为两个正整数n和b,第二行为1~n的排列。

【数据规模】

对于30%的数据中,满足n≤100;

对于60%的数据中,满足n≤1000;

对于100%的数据中,满足n≤100000,1≤b≤n。

输出格式:

输出一个整数,即中位数为b的连续子序列个数。

from 黄学长

找到b在数列中的位置设为point,比b大的赋值为-1,比b小的赋值为1;

然后求出sum[i,point]的值出现了几次记为lfre[sum[i,point]]++; ans += lfre[sum[i,point]]*rfre[-sum[i,point]];

由于c++数组不能是负数,所以稍微处理一下

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int maxn=1e6+7;
 5 int n,b,tmp,ans;
 6 int a[maxn],sum[maxn],lft[maxn],rgt[maxn],t[maxn];
 7 int main(){
 8   cin>>n>>b;
 9   for(int i=1;i<=n;i++) cin>>a[i];
10   for(int i=1;i<=n;i++){
11     if(a[i]>b) t[i]=1;
12     if(a[i]==b){t[i]=0;tmp=i;}
13     if(a[i]<b) t[i]=-1; 
14   }
15   lft[n]=1;rgt[n]=1;
16   for(int i=tmp-1;i>=1;i--){
17     sum[i]=sum[i+1]+t[i];lft[sum[i]+n]++;
18   }
19   for(int i=tmp+1;i<=n;i++){
20     sum[i]=sum[i-1]+t[i];rgt[sum[i]+n]++;
21   }
22   for(int i=0;i<2*n;i++){
23     ans+=lft[i]*rgt[2*n-i];
24   }
25   cout<<ans<<endl;
26   return 0;
27 } 

第k大一般用二分

二分一个答案,将序列中大于它的数附为1,小于它的赋为-1,利用树状数组求顺序对,即中位数大于当前答案的区间的个数

如果这个值大了,说明当前二分的答案小了,就要r=mid+1当然这里指的是在数列中的下标

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <queue>
 4 #include <cstring>
 5 #include <algorithm>
 6 #define N 200005
 7 #define ll long long
 8 using namespace std;
 9 int a[100010];
10 int b[100010];
11 int c[2][400010];
12 int n;
13 ll k;
14 void add(int x,int y,int f){
15     for(;x<=400000;x+=(x&(-x))){
16         c[f][x]+=y;
17     }
18 }
19 int query(int x,int f){
20     int ret=0;
21     for(;x>0;x-=(x&(-x))){
22         ret+=c[f][x];
23     }
24     return ret;
25 }
26 bool check(int mid){
27     ll ret=0;
28     int tmp=0;
29     memset(c,0,sizeof(c));
30     add(N,1,0);
31     for(int i=1;i<=n;i++){
32         if(a[i]>=mid) tmp++;
33         if(i&1){
34             ret+=query(tmp*2-i+N,0);
35             add(tmp*2-i+N,1,1);
36         }
37         else{
38             ret+=query(tmp*2-i+N,1);
39             add(tmp*2-i+N,1,0);
40         }
41     }
42     return ret>=k;
43 }
44 int main(){
45     freopen("kth.in","r",stdin);
46     freopen("kth.out","w",stdout);
47     scanf("%d%lld",&n,&k);
48     for(int i=1;i<=n;i++){
49         scanf("%d",&a[i]);
50         b[i]=a[i];
51     }
52     sort(b+1,b+n+1);
53     int tmp=unique(b+1,b+n+1)-b-1;
54     for(int i=1;i<=n;i++){
55         a[i]=lower_bound(b+1,b+tmp+1,a[i])-b;
56     }
57     int l=1;
58     int r=tmp;
59     while(l+1<r){
60         int mid=l+r>>1;
61         if(check(mid)) l=mid;
62         else r=mid-1;
63     }
64     if(check(r)) cout<<b[r];
65     else cout<<b[l];
66     return 0;
67 }
68 /*--------------------- 
69 作者:zhn_666 
70 来源:CSDN 
71 原文:https://blog.csdn.net/zhn_666/article/details/78236482 
72 版权声明:本文为博主原创文章,转载请附上博文链接!*/

维护两个指针l,r

如果l~r这个区间的众数大于当前二分的值,那么[(1~l),r]都满足众数大于当前二分的值,

所以当一个区间满足时(从l到r,出现的数a[i],则s[a[i]]++,最后找最大的s[i])

l这个指针可以直接跳到r+1

原文地址:https://www.cnblogs.com/lcan/p/9695503.html