building - ビルの飾り付け (Building) Editorial by Mitsubachi


説明のため、 $a_i$ の中の最大値を $a_{\max}$ とします。

  • $dp[i][j]$ $:=$ $i$ 個目までのビルのみから選び、最後に選んだビルの高さが $j$ であるようなビルの選び方で個数が最大となるものの個数
  • とするDPを考えてみます。
    ここで、 $i$ 個目のビルを使う場合と使わない場合で分けて考えることで遷移は
  • $dp[i][j]=dp[i-1][j]$ $(j \neq a_i)$
  • $dp[i][a_i]=\max(dp[i-1][j],\max(dp[i-1][1],dp[i-1][2], \cdots , dp[i-1][a_i-1])+1)$
  • となります。
    また、答えは $\max(dp[n][0],dp[n][1], \cdots ,dp[n][a_{\max}])$ です。しかし、これを愚直に書くと $O(Na_{\max})$ となってしまい、間に合いません。

    DP 配列を使いまわすと $1$ つめの遷移は無視できます。
    $2$ つめの遷移は Range Max Query と呼ばれるもので、 segment tree を用いて $O(\log a_{\max})$ で処理することができます。
    C++の場合、atcoder/all もしくは atcoder/segtree を include することで使える ACLの segtree を用いると容易に実装できます。

    以上より、この問題は $O(N\log a_{\max})$ で解くことができました。

    なお、この問題は数列に対して LIS を求める問題と同値です。

    posted:
    last update: