CodeChef - CCDSAP Exam
slope trickの練習問題として解いた。
人iの初期位置をaiとし、人iを位置xに配置した場合の人1,2,...,iに関するコストの総和の最小値をfi(x)とする。
左右の境界を無視するとfi(x)=mint≤x−2fi−1(t)+∣x−ai∣=mint≤xfi−1(t−2)+∣x−ai∣と表せる。これだけなら普通のslope trickで解けるが実際には境界を越えられないところが難しい。
境界を越えたら大きなコストがかかるように、∣x−ai∣の代わりに定数Cを定めてCmax(0,1−x)+∣x−ai∣+Cmax(0,x−N)を追加することを考えたが、これは優先度付きキューに一つずつ挿入していく方法では難しそう。平衡二分木で多重集合を管理すればいけそう? → 平衡二分木slope trickを作ろうとしたが、最小値の更新が自明にはできない。おそらく任意のxについてf(x)の値が取得できる必要があって、実現方法がわからなかった。ただ、minがわからなくてもargminは容易に取得・更新できる。これだけわかれば最適解を貪欲に復元できそう。最適解における人iの位置をyiとする。yN=argminxfN(x)は既知であり、yi+1が既知であるときyiは
yi=min(xargminfi(x),yi+1−2)
と決定できる。argminが複数ある時はどれを取ってもよい。