From 0fc8c6c96fb1ec46aa82897980b5bc34551019b0 Mon Sep 17 00:00:00 2001 From: GitHub Date: Sun, 6 Oct 2024 10:45:51 +0000 Subject: [PATCH] [auto-verifier] docs commit c7dd77bcb98e4f05b983a86c9b4bc86a812c7b90 --- index.md | 11 +- other_algorithms/monge_shortest_path.hpp.md | 140 ++++++++++++++++++ other_algorithms/smawk.hpp.md | 12 +- .../concave_max_plus_convolution.test.cpp.md | 89 +++++++++++ .../monge_shortest_path.yuki705.test.cpp.md | 87 +++++++++++ 5 files changed, 334 insertions(+), 5 deletions(-) create mode 100644 other_algorithms/monge_shortest_path.hpp.md create mode 100644 other_algorithms/test/concave_max_plus_convolution.test.cpp.md create mode 100644 other_algorithms/test/monge_shortest_path.yuki705.test.cpp.md diff --git a/index.md b/index.md index 87946db6..609120e4 100644 --- a/index.md +++ b/index.md @@ -524,6 +524,9 @@ data: path: other_algorithms/longest_increasing_subsequence.hpp title: "Longest increasing subsequence \uFF08LIS, \u6700\u9577\u5897\u52A0\u90E8\ \u5206\u5217\uFF09" + - icon: ':heavy_check_mark:' + path: other_algorithms/monge_shortest_path.hpp + title: Shortest path of DAG with Monge weights - icon: ':warning:' path: other_algorithms/mos_algorithm.hpp title: "Mo's algorithm \uFF08\u533A\u9593\u30AF\u30A8\u30EA\u306B\u95A2\u3059\ @@ -536,7 +539,7 @@ data: title: "Slope trick \uFF08\u533A\u5206\u7DDA\u5F62\u51F8\u95A2\u6570\u306B\u95A2\ \u3059\u308B\u7279\u5B9A\u306E\u66F4\u65B0\u3092\u9AD8\u901F\u306B\u6271\u3046\ \u624B\u6CD5\uFF09" - - icon: ':warning:' + - icon: ':heavy_check_mark:' path: other_algorithms/smawk.hpp title: Totally Monotone Matrix Searching (SMAWK) - name: random @@ -1461,6 +1464,9 @@ data: - icon: ':heavy_check_mark:' path: other_algorithms/test/binary_lifting.yuki1013.test.cpp title: other_algorithms/test/binary_lifting.yuki1013.test.cpp + - icon: ':heavy_check_mark:' + path: other_algorithms/test/concave_max_plus_convolution.test.cpp + title: other_algorithms/test/concave_max_plus_convolution.test.cpp - icon: ':heavy_check_mark:' path: other_algorithms/test/dual_slope_trick.yuki2114.test.cpp title: other_algorithms/test/dual_slope_trick.yuki2114.test.cpp @@ -1470,6 +1476,9 @@ data: - icon: ':heavy_check_mark:' path: other_algorithms/test/longest_increasing_subsequence.test.cpp title: other_algorithms/test/longest_increasing_subsequence.test.cpp + - icon: ':heavy_check_mark:' + path: other_algorithms/test/monge_shortest_path.yuki705.test.cpp + title: other_algorithms/test/monge_shortest_path.yuki705.test.cpp - icon: ':heavy_check_mark:' path: other_algorithms/test/permutation_tree.yuki1720.test.cpp title: other_algorithms/test/permutation_tree.yuki1720.test.cpp diff --git a/other_algorithms/monge_shortest_path.hpp.md b/other_algorithms/monge_shortest_path.hpp.md new file mode 100644 index 00000000..51366745 --- /dev/null +++ b/other_algorithms/monge_shortest_path.hpp.md @@ -0,0 +1,140 @@ +--- +data: + _extendedDependsOn: [] + _extendedRequiredBy: [] + _extendedVerifiedWith: + - icon: ':heavy_check_mark:' + path: other_algorithms/test/monge_shortest_path.yuki705.test.cpp + title: other_algorithms/test/monge_shortest_path.yuki705.test.cpp + _isVerificationFailed: false + _pathExtension: hpp + _verificationStatusIcon: ':heavy_check_mark:' + attributes: + links: + - https://noshi91.hatenablog.com/entry/2022/01/13/001217 + - https://noshi91.hatenablog.com/entry/2023/02/18/005856 + bundledCode: "#line 2 \"other_algorithms/monge_shortest_path.hpp\"\n#include \n\ + #include \n\n// Shortest path of Monge-weighted graph\n// Variant of LARSCH\ + \ Algorithm: https://noshi91.hatenablog.com/entry/2023/02/18/005856\n// Complexity:\ + \ O(n log n)\n//\n// Given a directed graph with n vertices and weighted edges\n\ + // (w(i, j) = cost_callback(i, j) (i < j)),\n// this class calculates the shortest\ + \ path from vertex 0 to all other vertices.\ntemplate struct monge_shortest_path\ + \ {\n std::vector dist; // dist[i] = shortest distance from 0 to i\n\ + \ std::vector amin; // amin[i] = previous vertex of i in the shortest\ + \ path\n\n template void _check(int i, int k, F cost_callback) {\n\ + \ if (i <= k) return;\n if (Cost c = dist[k] + cost_callback(k,\ + \ i); c < dist[i]) dist[i] = c, amin[i] = k;\n }\n\n template \ + \ void _rec_solve(int l, int r, F cost_callback) {\n if (r - l == 1) return;\n\ + \n const int m = (l + r) / 2;\n for (int k = amin[l]; k <= amin[r];\ + \ ++k) _check(m, k, cost_callback);\n\n _rec_solve(l, m, cost_callback);\n\ + \ for (int k = l + 1; k <= m; ++k) _check(r, k, cost_callback);\n \ + \ _rec_solve(m, r, cost_callback);\n }\n\n template Cost solve(int\ + \ n, F cost_callback) {\n assert(n > 0);\n dist.resize(n);\n \ + \ amin.assign(n, 0);\n\n dist[0] = Cost();\n for (int i = 1;\ + \ i < n; ++i) dist[i] = cost_callback(0, i);\n\n _rec_solve(0, n - 1, cost_callback);\n\ + \n return dist.back();\n }\n\n template int num_edges()\ + \ const {\n int ret = 0;\n for (int c = (int)amin.size() - 1; c\ + \ >= 0; c = amin[c]) ++ret;\n return ret;\n }\n};\n\n// Find shortest\ + \ path length from 0 to n - 1 with k edges, min_edges <= k <= max_edges\n// https://noshi91.hatenablog.com/entry/2022/01/13/001217\n\ + template \nCost monge_shortest_path_with_specified_edges(int\ + \ n, int min_edges, int max_edges,\n \ + \ Cost max_abs_cost, F cost_callback) {\n\n assert(1 <= n);\n assert(0\ + \ <= min_edges);\n assert(min_edges <= max_edges);\n assert(max_edges <=\ + \ n - 1);\n\n monge_shortest_path msp;\n\n auto eval = [&](Cost p)\ + \ -> Cost {\n msp.solve(n, [&](int i, int j) { return cost_callback(i,\ + \ j) - p; });\n return -msp.dist.back() - p * (p < 0 ? max_edges : min_edges);\n\ + \ };\n\n Cost lo = -max_abs_cost * 3, hi = max_abs_cost * 3;\n\n while\ + \ (lo + 1 < hi) {\n Cost p = (lo + hi) / 2, f = eval(p), df = eval(p +\ + \ 1) - f;\n if (df == Cost()) {\n return -f;\n } else\ + \ {\n (df < Cost() ? lo : hi) = p;\n }\n }\n\n Cost flo\ + \ = eval(lo), fhi = eval(hi);\n\n return flo < fhi ? -flo : -fhi;\n}\n" + code: "#pragma once\n#include \n#include \n\n// Shortest path of\ + \ Monge-weighted graph\n// Variant of LARSCH Algorithm: https://noshi91.hatenablog.com/entry/2023/02/18/005856\n\ + // Complexity: O(n log n)\n//\n// Given a directed graph with n vertices and weighted\ + \ edges\n// (w(i, j) = cost_callback(i, j) (i < j)),\n// this class calculates\ + \ the shortest path from vertex 0 to all other vertices.\ntemplate \ + \ struct monge_shortest_path {\n std::vector dist; // dist[i] = shortest\ + \ distance from 0 to i\n std::vector amin; // amin[i] = previous vertex\ + \ of i in the shortest path\n\n template void _check(int i, int k,\ + \ F cost_callback) {\n if (i <= k) return;\n if (Cost c = dist[k]\ + \ + cost_callback(k, i); c < dist[i]) dist[i] = c, amin[i] = k;\n }\n\n \ + \ template void _rec_solve(int l, int r, F cost_callback) {\n \ + \ if (r - l == 1) return;\n\n const int m = (l + r) / 2;\n for\ + \ (int k = amin[l]; k <= amin[r]; ++k) _check(m, k, cost_callback);\n\n \ + \ _rec_solve(l, m, cost_callback);\n for (int k = l + 1; k <= m; ++k)\ + \ _check(r, k, cost_callback);\n _rec_solve(m, r, cost_callback);\n \ + \ }\n\n template Cost solve(int n, F cost_callback) {\n assert(n\ + \ > 0);\n dist.resize(n);\n amin.assign(n, 0);\n\n dist[0]\ + \ = Cost();\n for (int i = 1; i < n; ++i) dist[i] = cost_callback(0, i);\n\ + \n _rec_solve(0, n - 1, cost_callback);\n\n return dist.back();\n\ + \ }\n\n template int num_edges() const {\n int ret = 0;\n\ + \ for (int c = (int)amin.size() - 1; c >= 0; c = amin[c]) ++ret;\n \ + \ return ret;\n }\n};\n\n// Find shortest path length from 0 to n - 1 with\ + \ k edges, min_edges <= k <= max_edges\n// https://noshi91.hatenablog.com/entry/2022/01/13/001217\n\ + template \nCost monge_shortest_path_with_specified_edges(int\ + \ n, int min_edges, int max_edges,\n \ + \ Cost max_abs_cost, F cost_callback) {\n\n assert(1 <= n);\n assert(0\ + \ <= min_edges);\n assert(min_edges <= max_edges);\n assert(max_edges <=\ + \ n - 1);\n\n monge_shortest_path msp;\n\n auto eval = [&](Cost p)\ + \ -> Cost {\n msp.solve(n, [&](int i, int j) { return cost_callback(i,\ + \ j) - p; });\n return -msp.dist.back() - p * (p < 0 ? max_edges : min_edges);\n\ + \ };\n\n Cost lo = -max_abs_cost * 3, hi = max_abs_cost * 3;\n\n while\ + \ (lo + 1 < hi) {\n Cost p = (lo + hi) / 2, f = eval(p), df = eval(p +\ + \ 1) - f;\n if (df == Cost()) {\n return -f;\n } else\ + \ {\n (df < Cost() ? lo : hi) = p;\n }\n }\n\n Cost flo\ + \ = eval(lo), fhi = eval(hi);\n\n return flo < fhi ? -flo : -fhi;\n}\n" + dependsOn: [] + isVerificationFile: false + path: other_algorithms/monge_shortest_path.hpp + requiredBy: [] + timestamp: '2024-10-06 15:03:01+09:00' + verificationStatus: LIBRARY_ALL_AC + verifiedWith: + - other_algorithms/test/monge_shortest_path.yuki705.test.cpp +documentation_of: other_algorithms/monge_shortest_path.hpp +layout: document +title: Shortest path of DAG with Monge weights +--- + +$n$ 頂点の DAG で辺重みが Monge となるようなものに対して最短路長を高速に求める. [1] で紹介されている簡易版 LARSCH Algorithm が実装されていて,計算量は $O(n \log n)$ . + +また,辺数が `min_edges` 以上 `max_edges` 以下であるようなものに限った最短路長を高速に求めることも可能(計算量にさらに重み二分探索の $\log$ がつく). + +## 使用方法 + +### 最短路長の計算 + +```cpp +auto f = [&](int s, int t) -> Cost { + // +}; + +monge_shortest_path msp; +Cost ret = msp.solve(n, f); +``` + +### 辺の本数の下限・上限を指定した最短路長の計算 + +```cpp +auto f = [&](int s, int t) -> Cost { + // +}; + +int n; // 頂点数 +int l, r; // 辺の本数が [l, r] の範囲に収まる最短路を見つけたい +Cost max_weight; // f() が返す値の絶対値の上界 + +Cost ret = monge_shortest_path_with_specified_edges(n, l, r, max_weight, f); +``` + +## 問題例 + +- [No.705 ゴミ拾い Hard - yukicoder](https://yukicoder.me/problems/no/705) +- [AtCoder Beginner Contest 218 H - Red and Blue Lamps](https://atcoder.jp/contests/abc218/tasks/abc218_h) +- [東京海上日動プログラミングコンテスト2024(AtCoder Beginner Contest 355) G - Baseball](https://atcoder.jp/contests/abc355/tasks/abc355_g) +- [東北大学プログラミングコンテスト 2022 K - Lebesgue Integral](https://atcoder.jp/contests/tupc2022/tasks/tupc2022_k) + +## Links + +- [1] [簡易版 LARSCH Algorithm - noshi91のメモ](https://noshi91.hatenablog.com/entry/2023/02/18/005856) +- [2] [Aliens DP における二分探索の色々 - noshi91のメモ](https://noshi91.hatenablog.com/entry/2023/11/20/052227#fn-c9578a2a) diff --git a/other_algorithms/smawk.hpp.md b/other_algorithms/smawk.hpp.md index fd10a9a0..a12924d5 100644 --- a/other_algorithms/smawk.hpp.md +++ b/other_algorithms/smawk.hpp.md @@ -2,10 +2,13 @@ data: _extendedDependsOn: [] _extendedRequiredBy: [] - _extendedVerifiedWith: [] + _extendedVerifiedWith: + - icon: ':heavy_check_mark:' + path: other_algorithms/test/concave_max_plus_convolution.test.cpp + title: other_algorithms/test/concave_max_plus_convolution.test.cpp _isVerificationFailed: false _pathExtension: hpp - _verificationStatusIcon: ':warning:' + _verificationStatusIcon: ':heavy_check_mark:' attributes: links: - http://web.cs.unlv.edu/larmore/Courses/CSC477/monge.pdf @@ -98,8 +101,9 @@ data: path: other_algorithms/smawk.hpp requiredBy: [] timestamp: '2022-11-14 22:38:59+09:00' - verificationStatus: LIBRARY_NO_TESTS - verifiedWith: [] + verificationStatus: LIBRARY_ALL_AC + verifiedWith: + - other_algorithms/test/concave_max_plus_convolution.test.cpp documentation_of: other_algorithms/smawk.hpp layout: document title: Totally Monotone Matrix Searching (SMAWK) diff --git a/other_algorithms/test/concave_max_plus_convolution.test.cpp.md b/other_algorithms/test/concave_max_plus_convolution.test.cpp.md new file mode 100644 index 00000000..efd265b5 --- /dev/null +++ b/other_algorithms/test/concave_max_plus_convolution.test.cpp.md @@ -0,0 +1,89 @@ +--- +data: + _extendedDependsOn: + - icon: ':heavy_check_mark:' + path: other_algorithms/smawk.hpp + title: Totally Monotone Matrix Searching (SMAWK) + _extendedRequiredBy: [] + _extendedVerifiedWith: [] + _isVerificationFailed: false + _pathExtension: cpp + _verificationStatusIcon: ':heavy_check_mark:' + attributes: + '*NOT_SPECIAL_COMMENTS*': '' + PROBLEM: https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary + links: + - https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary + bundledCode: "#line 1 \"other_algorithms/test/concave_max_plus_convolution.test.cpp\"\ + \n#define PROBLEM \"https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary\"\ + \n\n#line 2 \"other_algorithms/smawk.hpp\"\n#include \n#include \n\ + #include \n#include \n#include \n#include \n\ + \n// SMAWK: finding minima of totally monotone function f(i, j) (0 <= i < N, 0\ + \ <= j < M) for each i\n// Constraints: every submatrix of f(i, j) is monotone.\n\ + // Complexity: O(N + M)\n// Option: `Memorization`: Memorize all query results\ + \ using hashmaps, effective when each query\n// requires heavy complexity Rererence:\n\ + // https://topcoder-g-hatena-ne-jp.jag-icpc.org/spaghetti_source/20120923/1348327542.html\n\ + // http://web.cs.unlv.edu/larmore/Courses/CSC477/monge.pdf\n// Verify: https://codeforces.com/contest/1423/submission/98368491\n\ + template struct SMAWK {\n std::vector> minima;\n std::function oracle;\n std::vector> memo;\n T _query(int i, int j) {\n if (Memorization)\n \ + \ return memo[i].count(j) ? memo[i][j] : (memo[i][j] = oracle(i, j));\n \ + \ else\n return oracle(i, j);\n }\n\n void _smawk_rec(const\ + \ std::vector &js, int ib, int ie, int id) {\n if (ib > ie) return;\n\ + \ std::vector js2;\n int i = ib;\n for (auto j : js)\ + \ {\n while (!js2.empty() and _query(i, js2.back()) >= _query(i, j))\ + \ js2.pop_back(), i -= id;\n if (int(js2.size()) != (ie - ib) / id)\ + \ js2.push_back(j), i += id;\n }\n _smawk_rec(js2, ib + id, ie,\ + \ id * 2);\n\n for (int i = ib, q = 0; i <= ie; i += id * 2) {\n \ + \ int jt = (i + id <= ie ? minima[i + id].first : js.back());\n \ + \ T fm = 0;\n bool init = true;\n for (; q < int(js.size());\ + \ ++q) {\n T fq = _query(i, js[q]);\n if (init or\ + \ fm > fq) fm = fq, minima[i] = std::make_pair(js[q], fq);\n init\ + \ = false;\n if (js[q] == jt) break;\n }\n }\n\ + \ }\n SMAWK(int N, int M, std::function oracle_) : minima(N),\ + \ oracle(oracle_) {\n if (Memorization) memo.resize(N);\n std::vector\ + \ js(M);\n std::iota(js.begin(), js.end(), 0);\n _smawk_rec(js,\ + \ 0, N - 1, 1);\n }\n};\n\n// Concave max-plus convolution\n// b must be concave\n\ + // Complexity: O(n + m)\n// Verify: https://www.codechef.com/problems/MAXPREFFLIP\n\ + template \nstd::vector concave_max_plus_convolution(const std::vector\ + \ &a, const std::vector &b) {\n const int n = a.size(), m = b.size();\n\n\ + \ auto is_concave = [&](const std::vector &u) -> bool {\n for (int\ + \ i = 1; i + 1 < int(u.size()); ++i) {\n if (u[i - 1] + u[i + 1] >\ + \ u[i] + u[i]) return false;\n }\n return true;\n };\n\n bool\ + \ a_concave = is_concave(a), b_concave = is_concave(b);\n assert(a_concave\ + \ or b_concave);\n if (!b_concave) return concave_max_plus_convolution(b,\ + \ a);\n\n auto select = [&](int i, int j) -> S {\n int aidx = j, bidx\ + \ = i - j;\n if (bidx < 0 or bidx >= m or aidx >= n) return INF;\n \ + \ return -(a[aidx] + b[bidx]);\n };\n SMAWK sm(n + m - 1, n,\ + \ select);\n std::vector ret;\n for (auto x : sm.minima) ret.push_back(-x.second);\n\ + \ return ret;\n}\n#line 4 \"other_algorithms/test/concave_max_plus_convolution.test.cpp\"\ + \n\n#include \n#line 7 \"other_algorithms/test/concave_max_plus_convolution.test.cpp\"\ + \nusing namespace std;\n\nint main() {\n cin.tie(nullptr);\n ios::sync_with_stdio(false);\n\ + \n int N, M;\n cin >> N >> M;\n vector A(N), B(M);\n for (auto\ + \ &a : A) cin >> a, a = -a;\n for (auto &b : B) cin >> b, b = -b;\n\n auto\ + \ ret = concave_max_plus_convolution(B, A);\n\n for\ + \ (int i = 0; i < N + M - 1; ++i) cout << -ret[i] << \" \\n\"[i + 1 == N + M -\ + \ 1];\n}\n" + code: "#define PROBLEM \"https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary\"\ + \n\n#include \"../smawk.hpp\"\n\n#include \n#include \nusing\ + \ namespace std;\n\nint main() {\n cin.tie(nullptr);\n ios::sync_with_stdio(false);\n\ + \n int N, M;\n cin >> N >> M;\n vector A(N), B(M);\n for (auto\ + \ &a : A) cin >> a, a = -a;\n for (auto &b : B) cin >> b, b = -b;\n\n auto\ + \ ret = concave_max_plus_convolution(B, A);\n\n for\ + \ (int i = 0; i < N + M - 1; ++i) cout << -ret[i] << \" \\n\"[i + 1 == N + M -\ + \ 1];\n}\n" + dependsOn: + - other_algorithms/smawk.hpp + isVerificationFile: true + path: other_algorithms/test/concave_max_plus_convolution.test.cpp + requiredBy: [] + timestamp: '2024-10-06 15:03:32+09:00' + verificationStatus: TEST_ACCEPTED + verifiedWith: [] +documentation_of: other_algorithms/test/concave_max_plus_convolution.test.cpp +layout: document +redirect_from: +- /verify/other_algorithms/test/concave_max_plus_convolution.test.cpp +- /verify/other_algorithms/test/concave_max_plus_convolution.test.cpp.html +title: other_algorithms/test/concave_max_plus_convolution.test.cpp +--- diff --git a/other_algorithms/test/monge_shortest_path.yuki705.test.cpp.md b/other_algorithms/test/monge_shortest_path.yuki705.test.cpp.md new file mode 100644 index 00000000..9a307384 --- /dev/null +++ b/other_algorithms/test/monge_shortest_path.yuki705.test.cpp.md @@ -0,0 +1,87 @@ +--- +data: + _extendedDependsOn: + - icon: ':heavy_check_mark:' + path: other_algorithms/monge_shortest_path.hpp + title: Shortest path of DAG with Monge weights + _extendedRequiredBy: [] + _extendedVerifiedWith: [] + _isVerificationFailed: false + _pathExtension: cpp + _verificationStatusIcon: ':heavy_check_mark:' + attributes: + '*NOT_SPECIAL_COMMENTS*': '' + PROBLEM: https://yukicoder.me/problems/no/705 + links: + - https://yukicoder.me/problems/no/705 + bundledCode: "#line 1 \"other_algorithms/test/monge_shortest_path.yuki705.test.cpp\"\ + \n#define PROBLEM \"https://yukicoder.me/problems/no/705\"\n#line 2 \"other_algorithms/monge_shortest_path.hpp\"\ + \n#include \n#include \n\n// Shortest path of Monge-weighted\ + \ graph\n// Variant of LARSCH Algorithm: https://noshi91.hatenablog.com/entry/2023/02/18/005856\n\ + // Complexity: O(n log n)\n//\n// Given a directed graph with n vertices and weighted\ + \ edges\n// (w(i, j) = cost_callback(i, j) (i < j)),\n// this class calculates\ + \ the shortest path from vertex 0 to all other vertices.\ntemplate \ + \ struct monge_shortest_path {\n std::vector dist; // dist[i] = shortest\ + \ distance from 0 to i\n std::vector amin; // amin[i] = previous vertex\ + \ of i in the shortest path\n\n template void _check(int i, int k,\ + \ F cost_callback) {\n if (i <= k) return;\n if (Cost c = dist[k]\ + \ + cost_callback(k, i); c < dist[i]) dist[i] = c, amin[i] = k;\n }\n\n \ + \ template void _rec_solve(int l, int r, F cost_callback) {\n \ + \ if (r - l == 1) return;\n\n const int m = (l + r) / 2;\n for\ + \ (int k = amin[l]; k <= amin[r]; ++k) _check(m, k, cost_callback);\n\n \ + \ _rec_solve(l, m, cost_callback);\n for (int k = l + 1; k <= m; ++k)\ + \ _check(r, k, cost_callback);\n _rec_solve(m, r, cost_callback);\n \ + \ }\n\n template Cost solve(int n, F cost_callback) {\n assert(n\ + \ > 0);\n dist.resize(n);\n amin.assign(n, 0);\n\n dist[0]\ + \ = Cost();\n for (int i = 1; i < n; ++i) dist[i] = cost_callback(0, i);\n\ + \n _rec_solve(0, n - 1, cost_callback);\n\n return dist.back();\n\ + \ }\n\n template int num_edges() const {\n int ret = 0;\n\ + \ for (int c = (int)amin.size() - 1; c >= 0; c = amin[c]) ++ret;\n \ + \ return ret;\n }\n};\n\n// Find shortest path length from 0 to n - 1 with\ + \ k edges, min_edges <= k <= max_edges\n// https://noshi91.hatenablog.com/entry/2022/01/13/001217\n\ + template \nCost monge_shortest_path_with_specified_edges(int\ + \ n, int min_edges, int max_edges,\n \ + \ Cost max_abs_cost, F cost_callback) {\n\n assert(1 <= n);\n assert(0\ + \ <= min_edges);\n assert(min_edges <= max_edges);\n assert(max_edges <=\ + \ n - 1);\n\n monge_shortest_path msp;\n\n auto eval = [&](Cost p)\ + \ -> Cost {\n msp.solve(n, [&](int i, int j) { return cost_callback(i,\ + \ j) - p; });\n return -msp.dist.back() - p * (p < 0 ? max_edges : min_edges);\n\ + \ };\n\n Cost lo = -max_abs_cost * 3, hi = max_abs_cost * 3;\n\n while\ + \ (lo + 1 < hi) {\n Cost p = (lo + hi) / 2, f = eval(p), df = eval(p +\ + \ 1) - f;\n if (df == Cost()) {\n return -f;\n } else\ + \ {\n (df < Cost() ? lo : hi) = p;\n }\n }\n\n Cost flo\ + \ = eval(lo), fhi = eval(hi);\n\n return flo < fhi ? -flo : -fhi;\n}\n#line\ + \ 3 \"other_algorithms/test/monge_shortest_path.yuki705.test.cpp\"\n\n#line 5\ + \ \"other_algorithms/test/monge_shortest_path.yuki705.test.cpp\"\n#include \n\ + #include \nusing namespace std;\n\nint main() {\n cin.tie(nullptr),\ + \ ios::sync_with_stdio(false);\n\n int N;\n cin >> N;\n vector A(N),\ + \ X(N), Y(N);\n for (auto &a : A) cin >> a;\n for (auto &x : X) cin >> x;\n\ + \ for (auto &y : Y) cin >> y;\n\n auto weight = [&](int j, int i) {\n \ + \ assert(j < i);\n --i;\n const long long dx = abs(A.at(i)\ + \ - X.at(j)), dy = Y.at(j);\n return dx * dx * dx + dy * dy * dy;\n \ + \ };\n\n monge_shortest_path msp;\n cout << msp.solve(N + 1,\ + \ weight) << '\\n';\n}\n" + code: "#define PROBLEM \"https://yukicoder.me/problems/no/705\"\n#include \"../monge_shortest_path.hpp\"\ + \n\n#include \n#include \n#include \nusing namespace\ + \ std;\n\nint main() {\n cin.tie(nullptr), ios::sync_with_stdio(false);\n\n\ + \ int N;\n cin >> N;\n vector A(N), X(N), Y(N);\n for (auto &a\ + \ : A) cin >> a;\n for (auto &x : X) cin >> x;\n for (auto &y : Y) cin >>\ + \ y;\n\n auto weight = [&](int j, int i) {\n assert(j < i);\n \ + \ --i;\n const long long dx = abs(A.at(i) - X.at(j)), dy = Y.at(j);\n\ + \ return dx * dx * dx + dy * dy * dy;\n };\n\n monge_shortest_path msp;\n cout << msp.solve(N + 1, weight) << '\\n';\n}\n" + dependsOn: + - other_algorithms/monge_shortest_path.hpp + isVerificationFile: true + path: other_algorithms/test/monge_shortest_path.yuki705.test.cpp + requiredBy: [] + timestamp: '2024-10-06 15:03:01+09:00' + verificationStatus: TEST_ACCEPTED + verifiedWith: [] +documentation_of: other_algorithms/test/monge_shortest_path.yuki705.test.cpp +layout: document +redirect_from: +- /verify/other_algorithms/test/monge_shortest_path.yuki705.test.cpp +- /verify/other_algorithms/test/monge_shortest_path.yuki705.test.cpp.html +title: other_algorithms/test/monge_shortest_path.yuki705.test.cpp +---