原文链接https://www.cnblogs.com/zhouzhendong/p/ARC101D.html
题目传送门 - ARC101D
题意
给定一个序列 A 。
定义一个序列 A 的中位数为:给 A 排序,得到的第 $leftlfloorcfrac{i}{2} ight floor+1$ 项的值。
序列 B 由序列 A 的所有连续子序列的中位数构成。
问序列 B 的中位数是多少。
序列中可能出现重复的数,$|A| leq 10^5$ 。
题解
注意这里说的“中位数”是题意里面定义的“中位数”。
首先考虑二分答案。
对于一个数 $k$ ,我们考虑判断最终序列的中位数是否 大于等于 $k$。
考虑将原序列中 大于等于 $k$ 的数全部设置为 $1$,小于 $k$ 的数设为 $-1$ 。那么,如果一个序列的和 非负,它原来的中位数就必然大于等于 $k$ 。
考虑用树状数组统计出中位数大于等于 $k$ 的序列个数 $ans$ 。
如果 $ansgeq cfrac{n(n+1)}4$ ,那么显然,序列 B 的中位数大于等于 $k$ 。
于是就可以在 $O(nlog^2 n)$ 的时间复杂度内解决这个问题了。
代码
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N=200005; int n,a[N],Ha[N],hs,k,f[N]; struct BIT{ int n,c[N]; void set(LL _n){ n=_n; memset(c,0,sizeof c); } void add(int x,int d){ for (;x<=n;x+=x&-x) c[x]+=d; } int ask(int x){ int ans=0; for (;x;x-=x&-x) ans+=c[x]; return ans; } }T; bool check(int k){ for (int i=1;i<=n;i++) f[i]=f[i-1]+(a[i]>=k?1:-1); T.set(n*2+1); LL ans=0; for (int i=0;i<=n;i++){ ans+=T.ask(f[i]+n+1); T.add(f[i]+n+1,1); } return ans>=1LL*n*(n+1)/4; } int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]),Ha[i]=a[i]; sort(Ha+1,Ha+n+1); hs=unique(Ha+1,Ha+n+1)-Ha-1; for (int i=1;i<=n;i++) a[i]=lower_bound(Ha+1,Ha+hs+1,a[i])-Ha; int L=1,R=hs,mid,ans=L; while (L<=R){ mid=(L+R)>>1; if (check(mid)) L=mid+1,ans=mid; else R=mid-1; } printf("%d",Ha[ans]); return 0; }