人間だけど競プロやる

解けなかった問題を理解できたら記事を投稿します。日本語の解説が見つからなかったもの中心。

Codeforces Round #669 (Div. 2) D. Discrete Centrifugal Jumps

Codeforces Round #669 (Div. 2) D. Discrete Centrifugal Jumps

この問題難しくね?
ちょっと理解が足りてないのでふわっとした説明になってます。

気づき

  1. min max の要素数が小さいのなら場合分けをしてみる(今回は4パターン)
  2. 場合分けをすることで、インデックスiに対して、移動できる位置を(場合分けの条件下で)1つに限定できる


……どうやって思いつくんでしょうね?
いろいろ手を動かすと、下に凸なビル群で、移動する両端のインデックスをl,rと置いたとき、lからの移動先がr一つに限定できるパターンと、lからrの間にmが存在して、lからmへと移動できて、lからの移動先が一つに定まらいパターンがあることがわかる。
どういったときにlからの移動先を一つに限定できるかというと、
a_l < a_r かつ max (a_{l+1}...a_{r-1}) < a_l のときに、lから移動先はr唯一に定まる。
(\because max (a_{l+1}...a_{r-1}) < a_lなので、a_l以上は存在しない)
逆に、a_l > a_r かつ max (a_{l+1}...a_{r-1}) < a_r のとき、lからの移動先は l+1...r-1 の間に存在し得る。(\because l < m < r にたいして、 a_l > a_m かつ max (a_{l+1}...a_{m-1}) < a_m が存在できる)
このとき、視点を変えることで、問題をシンプルにすることができる。つまり、lからrへの移動ではなく、rへ移動してくる移動元を考える。すると、a_l > a_r のとき、rへ移動してくる移動元はlの唯一に定まる。

f:id:bqn2:20200912002403p:plain
fig.1

同様にして、上に凸の場合も考えると、結局移動先(移動元)は4パターンあり、
(上記に加えてa_l = a_rの場合も考慮する必要がある)
任意のインデックスiにたいして、

  • a_i > a_{i+1} (下に凸)のとき、a_iより右側にある、最初のa_i以上のビル
  • a_i > a_{i-1} (下に凸)のとき、a_iより左側にある、最初のa_i以上のビル
  • a_i < a_{i+1} (上に凸)のとき、a_iより右側にある、最初のa_i以下のビル
  • a_i < a_{i-1} (上に凸)のとき、a_iより左側にある、最初のa_i以下のビル

が移動先(移動元)となる。
(当然i+1への移動を忘れないように)


以上からグラフをつくってDPか最短経路で問題は解ける。
移動先を求めるのは、セグメントツリーに対する二分探索が使える。
境界条件でバグりやすいので注意。
公式解説はstackを利用して頭がよいので、できれば理解しておきたい。