6
6
#include < vector>
7
7
8
8
// SMAWK: finding minima of totally monotone function f(i, j) (0 <= i < N, 0 <= j < M) for each i
9
- // Constraints: every submatrix of f(i, j) is monotone.
9
+ // Constraints: every submatrix of f(i, j) is monotone (= totally monotone) .
10
10
// Complexity: O(N + M)
11
11
// Reference:
12
12
// https://topcoder-g-hatena-ne-jp.jag-icpc.org/spaghetti_source/20120923/1348327542.html
@@ -46,8 +46,19 @@ std::vector<std::pair<int, T>> SMAWK(int N, int M, const std::function<T(int i,
46
46
return minima;
47
47
}
48
48
49
+ // Find minima of totally ANTI-monotone function f(i, j) (0 <= i < N, 0 <= j < M) for each i
50
+ // Constraints: every submatrix of f(i, j) is anti-monotone.
51
+ // Complexity: O(N + M)
52
+ template <class T >
53
+ std::vector<std::pair<int , T>>
54
+ SMAWKAntiMonotone (int N, int M, const std::function<T(int i, int j)> &weight) {
55
+ auto minima = SMAWK<T>(N, M, [&](int i, int j) -> T { return weight (i, M - 1 - j); });
56
+ for (auto &p : minima) p.first = M - 1 - p.first ;
57
+ return minima;
58
+ }
59
+
49
60
// Concave max-plus convolution
50
- // b must be concave
61
+ // **b MUST BE CONCAVE**
51
62
// Complexity: O(n + m)
52
63
// Verify: https://www.codechef.com/problems/MAXPREFFLIP
53
64
template <class S , S INF>
@@ -60,10 +71,7 @@ std::vector<S> concave_max_plus_convolution(const std::vector<S> &a, const std::
60
71
}
61
72
return true ;
62
73
};
63
-
64
- bool a_concave = is_concave (a), b_concave = is_concave (b);
65
- assert (a_concave or b_concave);
66
- if (!b_concave) return concave_max_plus_convolution<S, INF>(b, a);
74
+ assert (is_concave (b));
67
75
68
76
auto select = [&](int i, int j) -> S {
69
77
int aidx = j, bidx = i - j;
@@ -75,3 +83,61 @@ std::vector<S> concave_max_plus_convolution(const std::vector<S> &a, const std::
75
83
for (auto x : minima) ret.push_back (-x.second );
76
84
return ret;
77
85
}
86
+
87
+ // Concave min-plus convolution
88
+ // **b MUST BE CONCAVE**
89
+ // Complexity: O((n + m)log(n + m))
90
+ template <class S >
91
+ std::vector<S> concave_min_plus_convolution (const std::vector<S> &a, const std::vector<S> &b) {
92
+ const int n = a.size (), m = b.size ();
93
+
94
+ auto is_concave = [&](const std::vector<S> &u) -> bool {
95
+ for (int i = 1 ; i + 1 < int (u.size ()); ++i) {
96
+ if (u[i - 1 ] + u[i + 1 ] > u[i] + u[i]) return false ;
97
+ }
98
+ return true ;
99
+ };
100
+ assert (is_concave (b));
101
+
102
+ std::vector<S> ret (n + m - 1 );
103
+ std::vector<int > argmin (n + m - 1 , -1 );
104
+
105
+ // mat[i][j] = a[j] + b[i - j]
106
+ auto is_valid = [&](int i, int j) { return 0 <= i - j and i - j < m; };
107
+ auto has_valid = [&](int il, int ir, int jl, int jr) {
108
+ if (il >= ir or jl >= jr) return false ;
109
+ return is_valid (il, jl) or is_valid (il, jr - 1 ) or is_valid (ir - 1 , jl) or
110
+ is_valid (ir - 1 , jr - 1 );
111
+ };
112
+
113
+ auto rec = [&](auto &&self, int il, int ir, int jl, int jr) -> void {
114
+ if (!has_valid (il, ir, jl, jr)) return ;
115
+
116
+ if (is_valid (il, jr - 1 ) and is_valid (ir - 1 , jl)) {
117
+ auto select = [&](int i, int j) -> S { return a[j + jl] + b[(i + il) - (j + jl)]; };
118
+ const auto res = SMAWKAntiMonotone<S>(ir - il, jr - jl, select);
119
+ for (int idx = 0 ; idx < ir - il; ++idx) {
120
+ const int i = il + idx;
121
+ if (argmin[i] == -1 or res[idx].second < ret[i]) {
122
+ ret[i] = res[idx].second ;
123
+ argmin[i] = res[idx].first + jl;
124
+ }
125
+ }
126
+ } else {
127
+ if (const int di = ir - il, dj = jr - jl; di > dj) {
128
+ const int im = (il + ir) / 2 ;
129
+ self (self, il, im, jl, jr);
130
+ self (self, im, ir, jl, jr);
131
+ } else {
132
+ const int jm = (jl + jr) / 2 ;
133
+ self (self, il, ir, jl, jm);
134
+ self (self, il, ir, jm, jr);
135
+ }
136
+ }
137
+ };
138
+
139
+ rec (rec, 0 , n + m - 1 , 0 , n);
140
+
141
+ return ret;
142
+ // return argmin; // If you want argmin (0 <= argmin[idx] < len(a))
143
+ }
0 commit comments