まず、本を持ちながら移動しなければいけない距離は Σ|i-p[i]|
以上なのは明らかで、逆にこれで十分なことも言える。
本を持たずに移動する距離を最小化したい。
本の台を頂点として、隣どうしの台を辺で繋いだグラフを考える。
i
〜p[i]
の間の辺に+1するってのを累積和とかでやっておく。(これをd[0~n-2]
とする)
s = 0
の場合、i≠p[i]
な i の最大値を mi として、「d[0]
からd[mi-1]
までの間にある 0 の個数」*2 が求めたいもの。
これで 50 点が来る。
s が真ん中だった場合なんでダメなのかは、2,1,0
とかを考えると分かるように、開始地点を跨いでるだけだと追加コストが生える。
以下の事実に気づくのが重要
i → p[u]
へ輸送する道中にある j について、j → p[j]
を輸送するのに追加コストはかからない。
i から j に来て、一旦持ってたのを置いて j を運び、p[j]
についたら p[j]
を運び・・・というのを繰り返すといつか j に戻ってくるので、そこから i を運ぶのを再開すればいい、という感じ。
サブルーチン的なイメージ。
j を運んでる途中にもまたサブルーチン的なのが生えるかもしれない。
d[i]=0
の辺を切っていくつかの連結成分に分解してみる。
各連結成分は上の考察から、一番外側(両端)の頂点に到達できれば追加コストで全てを網羅できることが分かる。
求めたいものは(「s を含む連結成分の一番外側に到達するまでのコスト」+「d[i]=0
の辺の個数※」)*2 となる。
※:到達する必要のないものは除く。つまり、両端をi=p[i]
である限り削った後に残るもの。
さて、後者は簡単に求まるので、前者をどう求めるか。
s から連結成分内で 0-1BFS (or dijkstra)をする。遷移は、
- 隣接へコスト 1 で移動
i 〜 p[i]
の間にある頂点の全てにコスト 0 で移動
で、両端の距離が"前者"の答え。
このままでは後者の遷移のせいで2乗かかるので、setを使ってすでに「コスト 0 で移動」をされた頂点を省くことで、各頂点につき高々1回しか注目されずにすみ、全体で O(N log N) で求まる。
setの代わりに隣接リストを使えば線形にもなりそう。(少なくともUF使えばンマーカッア)