2019年11月19日火曜日

JOI2011 本戦 D - 歩くサンタクロース

ひとまず一次元の問題として考える。つまり、数直線上のある地点ttに降り立って、各点x1,x2,...,xnx_1, x_2, ..., x_nに行って帰る問題である。さらにx1x2...xnx_1 \le x_2 \le ...\le x_nと仮定する。最後に訪れる点をxkx_kとする時、総距離は

 2tx1+....+2txk1+txk+2txk+1+...+2txn \ 2|t-x_1| + .... + 2|t-x_{k-1}| + |t-x_{k}| + 2|t-x_{k+1}| + ... +2|t-x_n|

となる。絶対値関数の和は下に凸になり、区分する点の中央値で最小値を取ることを使えそうな気がする。しかし、係数が邪魔なので開いて並べる:

tx1,tx1,...,txk1,txk,txk+1,...,txn,txn |t-x_1|, |t-x_1|, ... , |t-x_{k-1}|, |t-x_{k}|, |t-x_{k+1}|, ... , |t-x_n|, |t-x_n|

これら2n12n-1個の点の真ん中にある点xlx_lは(奇数個だから)一点に定まるので、上の式にt=xlt=x_lを代入すると最小値が求まる。具体的には、右側にあるn1n-1個のxix_iを足して左側にあるn1n-1個のxix_iを引けばよい。最後に訪れる点をnn通り試せば答えがわかる。二次元の場合もまったく同じで、xx方向とyy方向について独立に求めてから和を取ればよい。

実装について。いろいろやり方はありそうだけど、ソートされた列に順序を保って挿入・削除する操作があって、さらに区間の和が高速に求まれば直接的にシミュレーションできるのでそれがもっとも簡単に見える。平衡二分木ならどちらもO(logN){O}(\log N)でできる。


けっきょく真ん中になりえる点は1個か2個しかないので、それを試すだけでよいらしい。途中で気づきたかった。