AtCoder Beginner Contest 373 F問題メモ

F - Knapsack with Diminishing Values

問題文

  • $N$ 種類の品物があり、 $i$ 種類目の品物の重みは $w_i$、価値は $v_i$ です。どの種類の品物も $10^{10}$ 個ずつあります。
  • 品物をいくつか選んで、容量 $W$ のバッグに入れます。
  • ただし、各品物につき、$k$ 個選ぶと $k^2$ のペナルティが科されます。
    • つまり、$i$ 種類目の品物を $k_i$ 個選んだとき、スコアは $k_i v_i - k_i^2$
  • 選んだ品物の重さの総和を $W$ 以下にしつつ、達成できるスコアの総和の最大値 $\displaystyle \sum_{i=1}^{N}k_i v_i - k_i^2$ を求めてください。

制約

  • $1 \leq N \leq 3000$
  • $1 \leq W \leq 3000$
  • $1 \leq w_i \leq W$
  • $1 \leq v_i \leq 10^9$
  • 入力はすべて整数

解法

以下の素直なナップサックDPを考える。

  • $\mathrm{DP}[i,j]:=i$ 番目の品物まで考慮し、重さ合計が $j$ の場合の最大スコア

通常のナップサックDP(のうち、同じ品物を何個でも選んで良い版)では、 各 $i$ につき、$j$ が小さい方から $\mathrm{DP}[i,j+w_i] \xleftarrow[\max]{} \mathrm{DP}[i-1,j]+v_i$ と 更新していくことで $O(W)$、全体 $O(NW)$ で更新できる。

しかし、今回は加算されるスコア $v_i$ が、それまで何個の同じ品物を選んだかによって変化するので上手くいかない。
(そして、その個数別にDPを管理してたら、$O(NW^2)$ となり間に合わない)

以下の性質を利用する。

$\mathrm{DP}[i,j]$ は、もらうDPで考えて、以下の中の最大値である。

  • $\mathrm{DP}[i-1,j-0w_i] + 0v_i - 0^2$
  • $\mathrm{DP}[i-1,j-1w_i] + 1v_i - 1^2$
  • $\mathrm{DP}[i-1,j-2w_i] + 2v_i - 2^2$
  • $\mathrm{DP}[i-1,j-3w_i] + 3v_i - 3^2$

$\mathrm{DP}[i,j]$ の更新にあたり最大値を取る更新元($j-k_iw_i$)を $\mathrm{argmax}(j)$ とする。
更新先・更新元の関係にある $j$ 同士は、$\mod{w_i}$ が等しい。

ここで、ある $(j_1,j_2)$ の組について、$\mod{w_i}$ が等しく、$j_1 \lt j_2$ ならば、$\mathrm{argmax}(j_1) \le \mathrm{argmax}(j_2)$ である。

証明

$\mod{w_i}$ が等しい同士にグループ分けすると、$j$ を増やすに従って $\mathrm{argmax}(j)$ は必ず広義単調増加する。

このような性質を Monotone といい、各 $j$ に対する最大値は Monotoe Minima を使うことで $O(W \log{W})$ で求められる。

よって、全体で $O(NW \log{W})$ に高速化される。

Python3

programming_algorithm/contest_history/atcoder/2024/0928_abc373.txt · 最終更新: 2024/09/28 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0