定义一个长度为奇数的区间的值为其所包含的的元素的中位数。中位数_百度百科
现给出n个数,求将所有长度为奇数的区间的值排序后,第K大的值为多少。
样例解释:
[l,r]表示区间的值
[1]:3
[2]:1
[3]:2
[4]:4
[1,3]:2
[2,4]:2
第三大是2
Input
第一行两个数n和k(1<=n<=100000,k<=奇数区间的数量)
第二行n个数,0<=每个数<2^31
Output
一个数表示答案。
Input示例
4 3
3 1 2 4
Output示例
2
题目大意:定义一段奇数长度区间的值为其中位数,求所有子区间的值的第k大。
题解:二分答案
如果二分第k大为t,寻找大于t的区间的个数。设s[i]为1--i大于t的数的个数。
如果一个区间的中位数大于t,那么s[r]-s[l-1]>(r-l+1)/2,整理一下
2*s[r]-r>2*s[l-1]-(l-1),用树状数组统计一下即可。
代码:
#include<iostream> #include<cstdio> #include<cstring> #define LL long long #define maxn 100009 using namespace std; int n,l,r,mid,ans,a[maxn],b[maxn],tree[maxn*3][3]; LL k; void add(int pos,int p){ if(pos<=0)return; for(;pos<=maxn*3;pos+=pos&(-pos))tree[pos][p]++; } LL getsum(int pos,int p){ LL all=0;if(pos<=0)return 0; for(;pos;pos-=pos&(-pos))all+=tree[pos][p]; return all; } bool check(int p){ LL s=0; memset(tree,0,sizeof(tree)); for(int i=1;i<=n;i++)b[i]=a[i]>=p?1:0,b[i]+=b[i-1]; for(int i=1;i<=n;i++)b[i]=2*b[i]-i+n; add(n,0);//??? for(int i=1;i<=n;i++){ s+=getsum(b[i],(i&1)^1); add(b[i],(i&1)); } return s>=k; } int main(){ scanf("%d%lld",&n,&k); for(int i=1;i<=n;i++)scanf("%d",&a[i]),r=max(r,a[i]); while(l<=r){ mid=(l+r)>>1; if(check(mid))ans=mid,l=mid+1; else r=mid-1; } printf("%d ",ans); return 0; }