1. 程式人生 > >求中位數為K的區間的數目

求中位數為K的區間的數目

優化 blog uri 出現的次數 reference 解決 排序 出現 code

給定一個長為 $n$ 的序列和常數 $k$,求此序列的中位數為 $k$ 的區間的數量。一個長為 $m$ 的序列的中位數定義為將此序列從小到大排序後第 $\lceil m / 2 \rceil$ 個數。

解法

直接考慮中位數等於 $k$ 的區間是比較困難的,我們轉而考慮中位數大於等於 $k$ 的區間個數。按題目中所采用中位數定義,一個序列的中位數大於等於 $k$ 當且僅當序列中大於等於 $k$ 的元素的數目超過序列長度的一半。

對於某個固定的 $k$,將序列中大於等於 $k$ 的元素替換成 $1$,小於 $k$ 的元素替換成 $-1$,則區間的中位數大於等於 $k$ 就等價於區間和大於 $0$ 。從而可以用樹狀數組求出區間和大於 $0$ 的區間個數。復雜度 $O(n\log n)$ 。

若中位數的定義改成排序後第 $\lceil (m +1)/ 2 \rceil$ 個數,只要將算法稍加修改即可。

優化

給定一個長度為 $n$ 的由 $-1$、$1$ 構成的序列 $a$,求區間和大於 $0$ 的區間數目。這個問題可以在 $O(n)$ 的時間內解決。
設 $a$ 序列的前綴和序列為 $s$,則當我們考慮以 $i$ 為右端點的滿足條件的區間數時,只需要知道 $s[1..i-1]$ 中小於 $s[i]$ 的元素的數目,把這個值記作 $c[i]$。而 $s[i]$ 和 $s[i-1]$ 必定相差 $1$ 或 $-1$ 。考慮 $a[i]=1$ 的情形,此時 $s[i] = s[i-1] + 1$,因此有 $c[i]$ 等於 $c[i-1]$ 加上 $s[i..i-1]$ 中 $s[i-1]$ 出現的次數。由於 $s[i]$ 最多有 $O(n)$ 個不同取值,我們可以用一個數組動態維護 $s[1..i]$ 中每個數出現的次數,這樣就可以 $O(1)$ 地由 $c[i-1]$ 算出 $c[i]$ 。

Reference

http://codeforces.com/blog/entry/18879#comment-238126

求中位數為K的區間的數目