2019年10月30日水曜日

JOI2018 予選 F - L番目のK番目の数

JOI2018 予選 F - L番目のK番目の数

0-based(A0,A1,...,AN1A_0, A_1, ..., A_{N-1})で考える。

書き出した数の中にxx以下の数がf(x)f(x)個あるとするとき、f(x)Lf(x) \ge Lとなるような最小のxxを求めればよい。この言い換えを元の数列(Ai)(A_i)の言葉でさらに言い換えると、次のようになる:

xx以下の数をKK個以上含むような部分列A[l,r)A[l, r)LL個以上存在するようなxxの中で最小のものを求めよ。

部分列A[l,r)A[l, r)xx以下の数をg(l,r,x)g(l, r, x)個含むとする。xxを固定した時にg(l,r,x)K、g(l, r, x) \ge Kであるようなl,r[0,N]l, r \in [0, N]が何組あるか数えられれば、二分探索で上のxxも求まりそう。具体的には次のように数える:

g(0,i,x)g(0, i, x)は部分列A[0,i)A[0, i)の中のxx以下の数の総数だから、累積和でテーブルを作っておけば任意のiiについてO(1)O(1)で求まる。そして、g(l,r,x)=g(0,r,x)g(0,l,x)Kg(0,r,x)K+g(0,l,x)g(l, r, x) = g(0, r, x) - g(0, l, x) \ge K \Leftrightarrow g(0, r, x) \ge K+g(0, l, x)であり、llを固定した時にこの式を満たすようなrrの数は二分探索で求まる。したがって、すべてのl[0,N]l \in [0, N]についてこのrrの数を求めて足し合わせると、それがf(x)f(x)である。

あとはf(x)f(x)について二分探索して、f(x)Lf(x) \ge Lであるような最小のxxを求めればそれが答えになっている。計算量はO(Nlog2N){\mathcal O}(N \log^2 N)