Processing math: 100%

トヨタ自動車プログラミングコンテスト2023#7(AtCoder Beginner Contest 328) G問題メモ

G - Cut and Reorder

問題

  • 長さ N の数列を、以下の操作を好きに繰り返して A1,...,AN から B1,...,BN にする
  • 操作1: 数列を好きな位置で切り刻んで好きな順で並べなおす。1箇所切り刻むのにコスト C
  • 操作2: 好きな i,k を選んで、Aik を加算する。コスト |k|
  • 最小コストを求めよ
  • 1N22
  • 1Ai,Bi,C1015
  • 実行制限時間 2.8秒
  • メモリ制限 512MB

解法

オーダーに 2N が含まれるbitDP解法なら、N=22 よりもうちょっと少なく設定されるだろうから別の解法かな?と変なメタ読みしたが、普通にbitDPだった。 いつもと違うメモリ制限も、想定解法が O(N2N) に対して O(N22N) を落とすためらしい。

DP[S] を以下で定義する。

  • S={S1,S2,...,Sn} として、A1,...,An を、BS1,BS2,...,BSn にするのにかかる最小コスト

配るDPで、DP[S] からの遷移を考える。

A1,...,An は決定しているので、次の An+1 から連続する、 操作1の結果のブロック1単位の切り出し方・移動先を全て試す。

S={2,3,6,7,8,9}

     1  2  3  4  5  6  7  8  9
A    o  o  o  o  o  o  -  -  -       o:決定済み  -:未決定

B    -  o  o  -  -  o  o  o  o
  • 長さ1のブロック A7 は、B1,B4,B5 に移せる
  • 長さ2のブロック [A7,A8] は、[B4,B5] に移せる
  • 長さ3のブロック [A7,A9] は、この S ではどこにも移せない

1ブロックの切り出しにつきコスト C かかり、移した先では操作2によって各要素の差の絶対値だけのコストがかかる。

  • pre[k,la,lb]= 長さ k のブロックで、それぞれ AlaBlb が左端であるもの同士を、操作2だけで合わせるコスト

O(N3) で事前計算でき、これを使うと遷移は(切り出し方・移動先)1箇所につき O(1) となる。

S をbitで表現して小さい方から計算していき、DP[{1,...,N}] が答えとなる。

計算量の考え方

1つの S に対する(切り出し方・移動先)の総数を考えると、 一見、ブロックの長さ O(N)、位置合わせ O(N)O(N2) に見える。
これだと、S2N 通りあるので O(N22N) となり少し厳しい。

だが実際は、S が大きくなる毎にブロック長の上限は狭まっていくし、長いブロックは位置合わせの回数も少なく済む。

公式Editorialによると、ブロックの長さに着目することで、 長さ k のブロックが試されるような S2Nk、 またそこからの位置合わせも Nk+1 箇所だけ試せばよいので、

  • Nk=12Nk(Nk+1)O(N2N)

となるらしい。

公式のサンプルコードは S の方から遷移先の l,r を探索しているが、 以下の自分のコードは、|S| を基準にまず遷移の長さ k を決めて、それを1つずつずらしている。
そのため少し遷移に無駄があって、どちらかというと O(N22N) を定数倍削減している感じだが、通った。
遷移回数も、3×108 ほどある。

Python3

programming_algorithm/contest_history/atcoder/2023/1111_abc328.txt · 最終更新: 2023/11/16 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0