F - 575 Editorial by maspy


公式解説と少し違いそうなので書きます。

DP で解きます. 二分探索は行いませんし,最適解の構造にも注目しません.

575 列を作るための操作は次のようなものです.

あとで作る必要がある数の多重集合 \(S\) を管理します.\(x=X[i]\) について,

  1. 第1グループの先頭の項として使う.\(x<5\) ならば \(S\)\(5-x\) を追加する.
  2. 第2グループの先頭の項として使う.\(x<7\) ならば \(S\)\(7-x\) を追加する.さらに \(S\)\(5\) を追加する.
  3. \(s\in S\) かつ \(x\leq s\) であるような \(s\) を選び,\(S\) から削除する.\(x<s\) ならば \(S\)\(s-x\) を追加する.

第 3 グループの 5 は,単に後で作る必要がある数リストに入れておけばよいことに注意しましょう.


\(S\) の要素としては \(2, 3, 4, 5\) のみが可能であることに注意すると,これで多項式時間の dp 解法にはなると思います.例えば

  • a: これまで選んだ第1グループの先頭の個数
  • b: これまで選んだ第2グループの先頭の個数
  • n2: \(S\) に含まれる \(2\) の個数
  • n3: \(S\) に含まれる \(3\) の個数
  • n4: \(S\) に含まれる \(4\) の個数
  • n5: \(S\) に含まれる \(5\) の個数

として,dp[a][b][n2][n3][n4][n5] := その状態に到達可能かの bool 値とします.

これは bool 値を持たせる dp ですが,典型的なテクニックで次元をひとつ落とせます.例えば

  • dp[a][b][n2][n3][n4] := 状態 (a,b,n2,n3,n4,n5) に到達可能な n5 としてありうる最小値

とします.あとは丁寧にすべての遷移を実装すれば,AC できます.第2グループの先頭をとる遷移は \(a>b\) のときだけ行える,など正しく実装しましょう.


メモリのことを考えましょう.

まず,a,b は \(N/3\) 以下のみ考えればよいです.これは達成可能な 575 列の個数が N/3 以下だからです.さらに,n2,n3,n4 は \(N/2\) 以下のみ考えればよいです.これは一度には n2,n3,n4 は合計で高々 \(1\) しか増減しないためです.同じようでも,n5 は \(2\) 増える可能性などがあり(第 2 グループの先頭を 2 で作った場合など),dp[a][b][n3][n4][n5] 等は良くないかもしれません.

適切な更新順をとることで,ひとつの dp テーブルの中で計算を完結させれば,dp[N/3][N/3][N/2][N/2][N/2] といった配列ですべてを計算できます.dp の値として char 型を選択すれば,MLE を回避できます.

a>=b, n2+n3+n4<=N/2 でもよいことなどを考えるともう少し余裕が持てるかもしれません.


計算量のことを考えます.雑に見積もるならば,上でとった空間の \(N\) 倍です.a>=b, n2+n3+n4<=N/2 まで考慮すると,\(N^6/864\)\(10^9\) ループ程度で上から抑えられます.これもかなり余裕のある評価で実装にはもっと枝狩り可能なので,詳細は詰めていませんがまあ最悪ケースでも AC できるかなという計算量になっていると思います. たとえば \(i\) ステップ目では a+b は \(i\) 以下で抑えたり,n2+n3+n4 は \(\min(i,N-i)\) で抑えたりできるので,TLE したらそういう枝狩りをすることが考えられます.

posted:
last update: