D - 連射王高橋君 Editorial by maspy


leading-zeros を許容しても最適解は変わらないので,以下の議論では leading-zeros を許容します(考察が少し簡潔になります).


次の関数 \(\mathrm{dfs}(x, k)\) を考えます:

  • \(x\)\(k\) 個以下の和として表すとき,桁数の和としてありうる最小値を \(\mathrm{dfs}(x, k)\) とする.

目標は,\(\mathrm{dfs}(price, k)\) の計算です.これは,次のような遷移を利用して再帰的に計算できます.

  • \(k\) 個すべてを使わない場合:\(\mathrm{dfs}(x, k-1)\) から遷移する.
  • \(k\) 個すべてを使う場合:\(1\) の位の総和を \(s\) とする.\(s\leq x\) かつ \(s\equiv x\pmod{10}\) が必要である.必要条件のもと,\(\mathrm{dfs}((x-s)/10, k)\) から遷移する.

これはメモ化再帰などで計算できます.(状態は \(K\)\(10\) で割った回数と繰り上がりの大きさの組で表せるため,配列をループする形の計算も可能です.)


探索する \(k\) の上限 \(K\) を固定した場合の計算量を考えましょう.\(P = \log(price)\) (price の桁数に相当)として計算量を記述します.

まず,\(1\) の位 \(k\) 個の和としてどのような \(s\) が可能かを前計算します.これは個数と和を状態とする dp で \(O(K^2)\) 時間で計算できます.

\(\mathrm{dfs}\) で探索する状態数を考えます.再帰の \(n\) 回目での \(x\) が,\([price / 10^n - K, price/10^n]\) 程度の区間に入るため,状態数は \(O(PK^2)\) となります.

各状態からは \(1\) の位の総和 (\(9K\) 以下)を探索するため,全体の計算量は \(O(PK^3)\) になります.


本問では,0, 1 が使えるという条件により,すべての数がコスト \(171\) 以下で作成できます.例えば

\(2431 = 1111 + 1110 + 0110 + 0100\)

のように \(0, 1\) のみからなる数に分解することを考えればよいです.したがって,探索の際には総コスト \(171\) 以下のもののみを対象よく,\(K = 85\) ととることができます.以上を適切に実装すれば,十分高速に解くことができます.

なお,\(K = 85\) というのはかなりゆるい評価であることは察せられると思います. 実際,\(K = 9\) としても正当になるようです.「+\(8\) 回以下しか使わない解が存在する」ことは上で確かめた通りですが,「+\(8\) 回以下しか使わない解が存在する」が成り立つかどうかは非自明だと思います.私にはすぐには証明は分かりませんでした.


本問で厄介なのは,コスト最小値だけでなく,最適解を与える数式をも構築しなければいけないところです.以下の解答例では,計算量を \(O(PK^4)\) に悪化させる代わりに常にコスト最小値とその構築方法をペアにして扱うことで実装を簡略化しています.

解答例:https://atcoder.jp/contests/arc005/submissions/42176888

posted:
last update: