Monotone Minima

Finds the minimum column of every row when the leftmost minimum columns are monotonically nondecreasing.

The matrix is accessed lazily through a function and does not need to be stored. Ties are resolved toward the leftmost column.

Import

import atcoder/extra/dp/monotone_minima

monotoneMinima

let center = @[0, 1, 1, 3]

let value =
  proc(row, column: int): int =
    let d = column - center[row]
    d * d

let argmin = monotoneMinima[int](
  center.len,
  5,
  value,
)

doAssert argmin == center

Complexity

For (H) rows and (W) columns, the number of matrix evaluations is

[ O((H+W)\log(H+1)). ]

divideAndConquerOptimization

Returns both the minimum value and the minimum column of every row.

let result = divideAndConquerOptimization[int](
  center.len,
  5,
  value,
)

echo result.minimum
echo result.argmin

divideAndConquerDpLayer

Computes one DP layer of the form

[ \mathrm{current}[j] = \min_i \left( \mathrm{previous}[i] + \mathrm{cost}(i,j) \right). ]

The caller must guarantee that the leftmost optimal (i) is monotonically nondecreasing with (j).

let previous = @[8, 3, 5, 9]

let cost =
  proc(candidate, state: int): int =
    let d = candidate - state
    d * d

let next = divideAndConquerDpLayer[int](
  previous,
  6,
  cost,
)

Preconditions

Practice problems

Show problems that can use this library (may reveal the intended technique)