2019年6月7日金曜日

JOI 2019 予選 E - イルミネーション

JOI 2019 予選 E - イルミネーション

木の番号を0,...,N10, ..., N-1として考える。選んだ木のうちいちばん右のものがx1x-1である場合の美しさの最大値をf(x)f(x)とする。xxと同時に選べない木 txt \le x でもっとも左にあるものをλ(x)\lambda (x)とするとき、ffの漸化式は

f(x)=Ax1+maxtλ(x1)f(t)f(x) = A_{x-1} + \max_{t \le \lambda (x-1)} f(t)

と書ける。

上の漸化式に従って素朴にDPするとO(n2){\mathcal O}(n^2)になるので、累積和S(x)=max0txf(t)S(x) = \max_{0 \le t \le x} f(t)で考える:

S(x)=max(f(x),S(x1))=max(Ax1+S(λ(x1)),S(x1)) \begin{aligned} S(x) & = \max(f(x), S(x-1)) \\ & = \max(A_{x-1} + S(\lambda(x-1)), S(x-1)) \end{aligned}

求める答えはS(n)S(n)なので、SSに関してDPすればよい。

さて、λ(x)\lambda(x)をどう求めるかが問題だが、長さNNのセグメント木λ\lambdaを作ってλ[x]:=x\lambda[x] := xと初期化し、各区間[L,R][L, R]を区間min\minLLに更新するという方法でテーブルを作った。この場合、計算量はO(N+MlogN){\mathcal O}(N + M\log N)になっている。

解説を見るとO(N+M){\mathcal O}(N+M)でできるらしい。長さNNの配列λ\lambdaをやはりλ[x]:=x\lambda [x] := xで初期化し、各クエリ(L,R)(L, R)λ[R]:=min(λ[R],L)\lambda[R] := \min(\lambda[R], L)で処理したあと、後ろからλ[x]:=min(λ[x],λ[x+1])\lambda[x] := \min (\lambda [x], \lambda [x+1])と更新していけばテーブルができている。なるほど……

線型でできそうという感じは確かにしたけど、少し複雑になると累積和的なやり方がぱっと出てこない。