Official

F - Happy Sequence Editorial by maroonrk


\(L\) を座標の最大値 \((=2 \times 10^5)\) とします. また,\(g_x\) (\(0 \leq x \leq L\)) を,\(g_x=\sum |B_i-x| - \sum |A_i-x|\) とします. \(A\) を適切に変更することで,すべての \(x\) に対して \(g_x \geq 0\) とできればよいです.

まず,最初に \(A_i=0\) に変更したと仮定します. すると行える操作は,以下のようになります.

  • \(A_i\) の値を \(1\) 増やす.この際のコストは,\(org\)\(A_i\) の入力で与えられた値,\(cur\) を現在の \(A_i\) の値とすると,\(C_i \times (2 \times (cur-org) +1)\)

\(D_{i,x}\) を,\(A_i=x\) のときに \(A_i\) をインクリメントするコストとします.

ある \(A_i\)\(x \rightarrow x+1\) と変化した際,\(g_0,g_1,\cdots,g_x\)\(1\) 減少し,\(g_{x+1},\cdots,g_L\)\(1\) 増加します. ここで,問題を次のように言い換えることができます.

  • 以下の操作を繰り返し,\(g\) のすべての要素を \(0\) 以上にせよ. そして,そのコストの総和を最小化せよ.
  • 操作:ある \(i\)\(x\) を選ぶ.同じ \((i,x)\) のペアは一度しか選べない. コスト \(D_{i,x}\) を払う.そして,\(g_0,g_1,\cdots,g_x\)\(1\) 減少させ,\(g_{x+1},\cdots,g_L\)\(1\) 増加させる.

本来は,\((i,x)\) を選ぶ前に \((i,x-1)\) を選ぶ必要がある,という条件があります.しかし,コストの値と,\(g_x\) の増減の様子から,その条件を課さなくても答えが変わらないことがわかります.

上記の問題を解きます. まず,全体で操作をする回数は,\(\sum B_i\) 回です. \(f(x)\) を,何らかの \(i\) について \((i,x)\) を選んだ個数,とします. \(g_x\) が全て非負,という条件を \(f(x)\) で書き直すことができます.全体の操作回数が定まっていることに注意すると,この条件は,ある整数列 \(E_x\) を用いて,以下のように言い換えられます.

  • すべての \(x\) について,\(\sum_{p=x}^L f(p) \leq E_x\).

これでまず,多項式時間の解法が得られます. 具体的には,整数の多重集合 \(S\) を用意し,\(x\) の降順に以下の操作をすればよいです.

  • すべての \(i\) について,\(D_{i,x}\)\(S\) に追加する.
  • \(S\) の要素のうち,小さい方から \(E_x\) を残し,残りを削除する.

この操作を愚直に行っていては間に合いません. そこで,\(S\) を次のようにして管理してみます.

  • 整数 \(t\),整数の配列 \(offset\) を保持する.
  • \(t\) 以上の要素は,\(S\) に含まれない.
  • \(t\) 未満の値 \(v\)\(S\) に含まれる個数は,\(offset[v]+getcnt(v,x)\) である. ここで,\(getcnt(v,x)\) は,\(D_{i,p}=v\) を満たす \((i,p)\) (\(x \leq p\)) の個数である.

すると,\(x+1 \rightarrow x\) と変化させる際,以下の操作をすればよいです.

  • \(E'_x=E_x-E_{x+1}\) とする.
  • \(D_{i,x}<t\) を満たす \(i\) の個数を \(V\) とする.
  • \(V>E'_x\) の場合は,\(t\)\(1\) ずつ減少させて,\(S\) のサイズがちょうど \(E_x\) になる場所を探す.
  • \(V<E'_x\) の場合は,\(t\)\(1\) ずつ増加させて,\(S\) のサイズがちょうど \(E_x\) になる場所を探す.

このアルゴリズムの計算量を評価します. ボトルネックは,\(t\) を増減させるパートです.

まず,\(t\)\(1\) 増減させるたびにかかる計算量を考えるます.\(K=max(C_i)\) とすると,これは \(O(K)\) でできます. 例えば,\(getcnt\) は一回あたり \(O(K)\) で計算できます. (前計算として,\(C_i\) の値ごとに分類し,累積和を求めておけばよいです) その他の操作もすべて \(O(K)\) で行えます.

最後に,\(t\) が増減する回数が合計で \(O(LK)\) であることを示します.

\(F_x\) を,\(D_{1,x},D_{2,x},\cdots,D_{N,x}\) の中で \(E'_x\) 番目に小さい数,とします. まず,\(E'_x\) について考えると,これは,\(x<B_i\) を満たす \(i\) の個数だとわかります.特に,\(E'_x \leq N\), \(E'_x \leq E_{x-1}\) です. 次に,\(\sum_{x=L}^1 |F_x-F_{x-1}|\)\(O(LK)\) であることを示します. そもそも \(F_x\) の値が \(O(LK)\) なので,\(F_x\) の減少分の総和を抑えることができればよいです. \(F'_{x-1}\) を,\(D_{1,x-1},D_{2,x-1},\cdots,D_{N,x-1}\) の中で \(E'_x\) 番目に小さい数,とします. そして,\(D_{i,,x}\) の定義に注目すると,\(F_x-K \leq F'_{x-1} \leq F_{x-1}\) が得られます.よって,\(F_x\) の増減の総量が \(O(NL)\) で抑えられました.

最後に,\(dist=|F_x-t|\) とします.\(t\)\(1\) 増減させるたびに,\(dist\)\(1\) 減少することがわかります. また,\(F_x\) の増減が \(O(LK)\) なので,\(dist\) が増加する総量も合計で \(O(LK)\) です.よって示されました.

よって,このアルゴリズムの計算量は \(O(N+LK^2)\) になります.

posted:
last update: