diff --git a/algorithm/smawk.hpp b/algorithm/smawk.hpp new file mode 100644 index 0000000..698b136 --- /dev/null +++ b/algorithm/smawk.hpp @@ -0,0 +1,71 @@ +#pragma once +#include +#include +namespace po167{ +// return argmax +// +// https://noshi91.github.io/Library/algorithm/smawk.cpp +template std::vector smawk(int N, int M, S select){ + auto f = [&](auto self, std::vector p,std::vector q) -> std::vector { + // reduce + std::vector n_q; + n_q.reserve(p.size()); + int k = -1; + for(auto x:q){ + while(!n_q.empty()){ + if(!select(p[k], n_q.back(), x)) break; + n_q.pop_back(); + k--; + } + if (k + 1 != (int)p.size()){ + n_q.push_back(x); + k++; + } + } + std::swap(n_q, q); + + int n = p.size(); + int m = q.size(); + + // recursive + if (n == 1){ + return q; + } + std::vector n_p; + n_p.reserve(n / 2); + + for (int i = 1; i < n; i += 2){ + n_p.push_back(p[i]); + } + + auto fr = self(self, n_p, q); + // interpolate + std::vector ans(n); + int l = 0, r = 0; + + for (int i = 0; i < n; i++){ + if(i & 1){ + ans[i] = fr[i / 2]; + l = r; + } else { + if (i + 1 != n) { + while (q[r] != fr[i / 2]) r++; + } else { + r = m - 1; + } + ans[i] = q[l]; + for (int j = l + 1; j <= r; j++){ + if(select(p[i], ans[i], q[j])){ + ans[i] = q[j]; + } + } + } + } + return ans; + }; + std::vector P(N), Q(M); + std::iota(P.begin(), P.end(), 0); + std::iota(Q.begin(), Q.end(), 0); + return f(f, P, Q); +} +} diff --git a/algorithm/sum_max_convolution.hpp b/algorithm/sum_max_convolution.hpp new file mode 100644 index 0000000..002fe7d --- /dev/null +++ b/algorithm/sum_max_convolution.hpp @@ -0,0 +1,38 @@ +#pragma once +#include +#include +#include "smawk.hpp" + +namespace po167{ +// X is convex upward +template +std::vector sum_max_convolution(std::vector X, std::vector Y){ + int n = X.size(); + int m = Y.size(); + std::vector ans(n + m - 1); + auto get = [&](int i, int j) -> T { + return X[i - j] + Y[j]; + }; + auto select = [&](int i, int j1, int j2) -> bool { + if (i < j2) return false; + if (i - j1 >= n) return true; + return get(i, j1) <= get(i, j2); + }; + const int D = 10; + if (std::min(n, m) <= D) { + for (int i = 0; i < n + m - 1; i++){ + int ind = std::max(0, i - n); + for (int j = ind + 1; j < m && j <= i; j++){ + if (select(i, ind, j)) ind = j; + } + ans[i] = get(i, ind); + } + return ans; + } + std::vector res = smawk(n + m - 1, m, select); + for (int i = 0; i < n + m - 1; i++){ + ans[i] = get(i, res[i]); + } + return ans; +} +} \ No newline at end of file diff --git a/test/algorithm/sum_min_conv.test.cpp b/test/algorithm/sum_min_conv.test.cpp new file mode 100644 index 0000000..4064597 --- /dev/null +++ b/test/algorithm/sum_min_conv.test.cpp @@ -0,0 +1,22 @@ +#define PROBLEM https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary + +#include "../../algorithm/sum_max_convolution.hpp" + +#include +#include + +int main(){ + std::ios::sync_with_stdio(false); + std::cin.tie(nullptr); + int N, M; + std::cin >> N >> M; + std::vector A(N), B(M); + for (auto &a : A) std::cin >> a, a *= -1; + for (auto &b : B) std::cin >> b, b *= -1; + auto c = po167::sum_max_convolution(A, B); + for (int i = 0; i < N + M - 1; i++){ + if (i) std::cout << " "; + std::cout << -c[i]; + } + std::cout << "\n"; +} \ No newline at end of file