標籤:memset 一個 class rac ++ highlight tps 複雜 連結
原文連結https://www.cnblogs.com/zhouzhendong/p/ARC101D.html
題目傳送門 - ARC101D題意
給定一個序列 A 。
定義一個序列 A 的中位元為:給 A 排序,得到的第 $\left\lfloor\cfrac{i}{2}\right\rfloor+1$ 項的值。
序列 B 由序列 A 的所有連續子序列的中位元構成。
問序列 B 的中位元是多少。
序列中可能出現重複的數,$|A| \leq 10^5$ 。
題解
注意這裡說的“中位元”是題意裡面定義的“中位元”。
首先考慮二分答案。
對於一個數 $k$ ,我們考慮判斷最終序列的中位元是否 大於等於 $k$。
考慮將原序列中 大於等於 $k$ 的數全部設定為 $1$,小於 $k$ 的數設為 $-1$ 。那麼,如果一個序列的和 非負,它原來的中位元就必然大於等於 $k$ 。
考慮用樹狀數組統計出中位元大於等於 $k$ 的序列個數 $ans$ 。
如果 $ans\geq \cfrac{n(n+1)}4$ ,那麼顯然,序列 B 的中位元大於等於 $k$ 。
於是就可以在 $O(n\log^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;elseR=mid-1;}printf("%d",Ha[ans]);return 0;}
AtCoder Regular Contest 101D - Median of Medians 二分答案 樹狀數組