ABC 107 / ARC 101 D Median of Medianを解いた。
ABC 107 / ARC 101 D Median of Median
D - Median of Medians
をpython(pypy)で解いた。
解説はこれ
https://img.atcoder.jp/arc101/editorial.pdf。
ほとんど解説どおりだけど、勉強のため自分の言葉で解説する。
解説
以下、 により、 以上の最小の整数を表す。
を長さ の整数列 の中央値とする。
すると、次の性質を満たす。
- 以上の の元は 以上
- はこの性質を満たすものの中で最大
つまり、となる。
ここで、は に関して、広義単調減少である。
従って、 は2分探索で求めることができる。
与えられた長さ の整数列を とする。
を2分探索における基準値とする。みたいなやつ。
に対して、をの中央値とする。
すると、上記の性質から、 以上の要素の個数が以上であるかにより、
2分探索すればよい。
のうち、x 以上の元を個以上もつものが以上かを調べれば良い。
ここで、 の元のうち 以上のものを に、 より小さいものを に置き換えれば、
のうち、となるものが以上かを調べれば良い。
個数の関係は和が 以上であることと同値なので、
のうち、となるものが以上かを調べれば良い。
各に対して、]とする。
ただし、とする。
以上をまとめると、
を調べれば良い。
これは、転倒数という名前らしい。
今回はBITを使って求めた。
次の文献を参考にした。
BITはこれ
http://hos.ac/slides/20140319_bit.pdf。
Binary indexed tree(BIT)をやった - kamojirobrothersのブログ。
転倒数BITはこれ
BITで転倒数を求める - Qiita。
プログラムはこれ。
def add(B,a,n):#リストに値を追加する関数 x = a while x <= n: B[x] += 1 x += x&(-x) def sums(B,a):#a番目までの和 x = a S = 0 while x != 0: S += B[x] x -= x&(-x) return S def invnumber(n, S):# #{(i,j)| i<j and S[i]<=S[j]} B = [0]*(n*2 + 1) invs = 0 for i in range(n): s = S[i] + n #BITで扱えるようにするために、nを加算した invs += sums(B, s) #i<j add(B, s, n*2) return invs N = int( input()) A = list( map( int, input().split())) R = max(A)+1 L = 0 c = (N*(N+1)//2 + 1)//2 while R - L > 1: M = (R+L)//2 S = [0]*(N+1) for i in range(1,N+1): if A[i-1] >= M: S[i] = S[i-1] + 1 else: S[i] = S[i-1] - 1 if invnumber(N+1,S) >= c: L = M else: R = M print(L)