求中位数为K的区间的数目

给定一个长为 $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

猜你喜欢

转载自www.cnblogs.com/Patt/p/9749951.html