C++ Library for Competitive Programming
#include "emthrm/dynamic_programming/convert_online_dp_to_offline_dp.hpp"
$i = 1, 2, \ldots, N$ に対して $\mathrm{dp}(i) = f_i(I)$ ($I \subseteq \lbrace 1, 2, \ldots, i - 1 \rbrace$) で表せるオンライン動的計画法を考える。
あるモノイド $(S, \cdot, e)$ が存在し、$\forall i \in \lbrace 1, 2, \ldots, N \rbrace$ に対して $f_i(I) = a_i \cdot (\prod_{j \in I} F_{ij}) \cdot b_i$ ($a_i, b_i, F_{ij} \in S,\ F_{ij} \text{ は } \mathrm{dp}(j) \text{ に依存してもよい}$) と表せるならば、複数のオフライン動的計画法に分割できる。
e.g. Stroll
モノイドを $(\mathbb{N}^N, +, \boldsymbol{0})$ とする。
$i = 0$ のとき
\[\mathrm{dp}(i) \mathrel{:=} \begin{pmatrix} 1 \\ 0 \\ \vdots \\ 0 \end{pmatrix} + \boldsymbol{0} \text{、}\]$i = 1, 2, \ldots, T$ のとき
\[\mathrm{dp}(i)_n \mathrel{:=} 0 + \sum_{j = 0}^{i - 1} \left(\sum_{a_m = n} dp(j)_{b_m} \cdot p_{m, i - j} + \sum_{b_m = n} dp(j)_{a_m} \cdot p_{m, i - j} \right) + 0\]と表せる。
$i = 1, 2, \ldots, N$ に対して $\mathrm{dp}(i) = f_i(I)$ ($I \subseteq \lbrace 1, 2, \ldots, i - 1 \rbrace$) で表せる動的計画法を考える。
$f_i(I)$ に対してある $j \in I$ が存在して $\mathrm{dp}(j)$ に依存するとき、これをオンライン動的計画法と呼ぶ。依存しないときはオフライン動的計画法と呼ぶ。
変換したオフライン動的計画法の時間計算量を $O(M(N))$ とおくと $O(M(N)\log{N})$
名前 | 効果 | 備考 |
---|---|---|
void convert_online_dp_to_offline_dp(const int n, const std::function<void(int, int, int)> induce); |
幅 $N$ の動的計画法に対してオフライン・オンライン変換を適用する。 |
induce(l, m, r) は $\mathrm{dp}(j)$ ($j = l, l + 1, \ldots, m - 1$) を $\mathrm{dp}(i)$ ($i = m, m + 1, \ldots, r - 1$) に適用する関数である。 |
https://atcoder.jp/contests/abc213/submissions/25161037
#ifndef EMTHRM_DYNAMIC_PROGRAMMING_CONVERT_ONLINE_DP_TO_OFFLINE_DP_HPP_
#define EMTHRM_DYNAMIC_PROGRAMMING_CONVERT_ONLINE_DP_TO_OFFLINE_DP_HPP_
#include <functional>
#include <numeric>
namespace emthrm {
void convert_online_dp_to_offline_dp(
const int n, const std::function<void(int, int, int)> induce) {
const auto solve = [induce](auto solve, const int l, const int r) -> void {
if (l + 1 == r) {
// dp(l) <- dp(l) ・ b_l
return;
}
const int m = std::midpoint(l, r);
solve(solve, l, m);
induce(l, m, r);
solve(solve, m, r);
};
if (n > 0) [[likely]] solve(solve, 0, n);
}
} // namespace emthrm
#endif // EMTHRM_DYNAMIC_PROGRAMMING_CONVERT_ONLINE_DP_TO_OFFLINE_DP_HPP_
#line 1 "include/emthrm/dynamic_programming/convert_online_dp_to_offline_dp.hpp"
#include <functional>
#include <numeric>
namespace emthrm {
void convert_online_dp_to_offline_dp(
const int n, const std::function<void(int, int, int)> induce) {
const auto solve = [induce](auto solve, const int l, const int r) -> void {
if (l + 1 == r) {
// dp(l) <- dp(l) ・ b_l
return;
}
const int m = std::midpoint(l, r);
solve(solve, l, m);
induce(l, m, r);
solve(solve, m, r);
};
if (n > 0) [[likely]] solve(solve, 0, n);
}
} // namespace emthrm