【洛谷U142585】中位數之中位數
阿新 • • 發佈:2020-11-27
題目
題目連結:https://www.luogu.com.cn/problem/U142585
給出一個長度為 \(n\) 的序列 \(a\),首先求出其所有區間的中位數,將這些中位數構成的集合記為 \(S\),求 \(S\) 中所有數的中位數。
這裡定義的中位數指:對於 \(m\) 個數,將其從小到大排序後,第 \((\frac{m}{2}+1)\) 個數即為中位數,例如 \((10,30,20)\) 的中位數為 \(20\),\((10,30,20,40)\) 的中位數為 \(30\),\((10,10,10,20,30)\) 的中位數為 \(10\)。
思路
套路性二分將序列轉化為 \(1,-1\) 序列。
然後做一遍字首和,問題轉化為 \(\sum^{n}_{i=1}\sum^{i-1}_{j=0}[s_i-s_j\geq 0]\)
用樹狀陣列計算一下即可。
時間複雜度 \(O(n\log n\log A)\)。其中 \(A=\max(a_i)\)。
程式碼
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=200010; int n,a[N],s[N]; ll sum; struct BIT { int c[N]; void add(int x,int v) { for (int i=x;i<N;i+=i&-i) c[i]+=v; } int query(int x) { int sum=0; for (int i=x;i;i-=i&-i) sum+=c[i]; return sum; } }bit; int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); int l=1,r=1e9,mid; while (l<=r) { mid=(l+r)>>1; sum=0; s[0]=1e5+1; memset(bit.c,0,sizeof(bit.c)); bit.add(s[0],1); for (int i=1;i<=n;i++) { if (a[i]>=mid) s[i]=s[i-1]+1; else s[i]=s[i-1]-1; sum+=2*bit.query(s[i])-i; bit.add(s[i],1); } if (sum>=0) l=mid+1; else r=mid-1; } printf("%d\n",l-1); return 0; }