pub(super) fn output_len(a_len: usize, b_len: usize) -> usizeExamples found in repository?
crates/competitive/src/math/min_plus_convolution/convex.rs (line 40)
36pub fn min_plus_convolution_convex_merge<T>(a: &[T], b: &[T]) -> Vec<T>
37where
38 T: Signed,
39{
40 let len = output_len(a.len(), b.len());
41 if len == 0 {
42 return Vec::new();
43 }
44 assert_finite(a);
45 assert_finite(b);
46 assert!(is_convex(a) && is_convex(b), "both inputs must be convex");
47 convex_merge(a, b)
48}
49
50pub(super) fn convex_merge<T>(a: &[T], b: &[T]) -> Vec<T>
51where
52 T: Signed,
53{
54 let len = output_len(a.len(), b.len());
55 let mut a_slopes = a.windows(2).map(|window| window[1] - window[0]);
56 let mut b_slopes = b.windows(2).map(|window| window[1] - window[0]);
57 let mut next_a = a_slopes.next();
58 let mut next_b = b_slopes.next();
59 let mut current = a[0] + b[0];
60 let mut result = Vec::with_capacity(len);
61 result.push(current);
62 while next_a.is_some() || next_b.is_some() {
63 let slope = match (next_a, next_b) {
64 (Some(left), Some(right)) if left <= right => {
65 next_a = a_slopes.next();
66 left
67 }
68 (Some(_), Some(right)) => {
69 next_b = b_slopes.next();
70 right
71 }
72 (Some(left), None) => {
73 next_a = a_slopes.next();
74 left
75 }
76 (None, Some(right)) => {
77 next_b = b_slopes.next();
78 right
79 }
80 (None, None) => break,
81 };
82 current += slope;
83 result.push(current);
84 }
85 result
86}
87
88/// Computes convolution when one input is convex using monotone divide and conquer.
89///
90/// # Panics
91///
92/// Panics unless both inputs are finite and at least one is convex.
93pub fn min_plus_convolution_convex_divide_and_conquer<T>(a: &[T], b: &[T]) -> Vec<T>
94where
95 T: Signed,
96{
97 let len = output_len(a.len(), b.len());
98 if len == 0 {
99 return Vec::new();
100 }
101 assert_finite(a);
102 assert_finite(b);
103 let (arbitrary, convex) = orient_one_convex(a, b);
104 convex_divide_and_conquer(arbitrary, convex)
105}
106
107pub(super) fn convex_divide_and_conquer<T>(arbitrary: &[T], convex: &[T]) -> Vec<T>
108where
109 T: Signed,
110{
111 let len = output_len(arbitrary.len(), convex.len());
112 let mut result = vec![T::zero(); len];
113
114 fn solve<T>(
115 arbitrary: &[T],
116 convex: &[T],
117 result: &mut [T],
118 rows: Range<usize>,
119 options: RangeInclusive<usize>,
120 ) where
121 T: Signed,
122 {
123 if rows.is_empty() {
124 return;
125 }
126 let row = (rows.start + rows.end) / 2;
127 let first = (*options.start()).max(row.saturating_sub(convex.len() - 1));
128 let last = (*options.end()).min(row).min(arbitrary.len() - 1);
129 let mut best_col = first;
130 let mut best_value = arbitrary[first] + convex[row - first];
131 for col in first + 1..=last {
132 let value = arbitrary[col] + convex[row - col];
133 if value < best_value {
134 best_value = value;
135 best_col = col;
136 }
137 }
138 result[row] = best_value;
139 solve(
140 arbitrary,
141 convex,
142 result,
143 rows.start..row,
144 *options.start()..=best_col,
145 );
146 solve(
147 arbitrary,
148 convex,
149 result,
150 row + 1..rows.end,
151 best_col..=*options.end(),
152 );
153 }
154
155 solve(
156 arbitrary,
157 convex,
158 &mut result,
159 0..len,
160 0..=arbitrary.len() - 1,
161 );
162 result
163}
164
165#[derive(Clone, Copy, Eq, PartialEq)]
166enum MatrixValue<T> {
167 Finite(T),
168 Infinite,
169}
170
171impl<T> Ord for MatrixValue<T>
172where
173 T: Ord,
174{
175 fn cmp(&self, other: &Self) -> Ordering {
176 match (self, other) {
177 (Self::Finite(left), Self::Finite(right)) => left.cmp(right),
178 (Self::Finite(_), Self::Infinite) => Ordering::Less,
179 (Self::Infinite, Self::Finite(_)) => Ordering::Greater,
180 (Self::Infinite, Self::Infinite) => Ordering::Equal,
181 }
182 }
183}
184
185impl<T> PartialOrd for MatrixValue<T>
186where
187 T: Ord,
188{
189 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
190 Some(self.cmp(other))
191 }
192}
193
194fn smawk<T, F>(rows: usize, cols: usize, cost: &F) -> Vec<usize>
195where
196 T: Ord,
197 F: Fn(usize, usize) -> T,
198{
199 fn solve<T, F>(rows: &[usize], cols: &[usize], cost: &F, argmins: &mut [usize])
200 where
201 T: Ord,
202 F: Fn(usize, usize) -> T,
203 {
204 if rows.is_empty() {
205 return;
206 }
207 let mut reduced = Vec::with_capacity(rows.len().min(cols.len()));
208 for &col in cols {
209 while let Some(&previous) = reduced.last() {
210 let row = rows[reduced.len() - 1];
211 if cost(row, col) <= cost(row, previous) {
212 reduced.pop();
213 } else {
214 break;
215 }
216 }
217 if reduced.len() < rows.len() {
218 reduced.push(col);
219 }
220 }
221 let odd_rows: Vec<_> = rows.iter().copied().skip(1).step_by(2).collect();
222 solve(&odd_rows, &reduced, cost, argmins);
223 let mut lower = 0;
224 for row_position in (0..rows.len()).step_by(2) {
225 let upper = if row_position + 1 < rows.len() {
226 let target = argmins[rows[row_position + 1]];
227 lower
228 + reduced[lower..]
229 .iter()
230 .position(|&col| col == target)
231 .expect("SMAWK odd-row minimum must remain in the reduced columns")
232 } else {
233 reduced.len() - 1
234 };
235 let row = rows[row_position];
236 let mut best = lower;
237 for position in lower + 1..=upper {
238 if cost(row, reduced[position]) <= cost(row, reduced[best]) {
239 best = position;
240 }
241 }
242 argmins[row] = reduced[best];
243 lower = upper;
244 }
245 }
246
247 let row_indices: Vec<_> = (0..rows).collect();
248 let col_indices: Vec<_> = (0..cols).collect();
249 let mut argmins = vec![0; rows];
250 solve(&row_indices, &col_indices, cost, &mut argmins);
251 argmins
252}
253
254/// Computes convolution when one input is convex using SMAWK in `O(n + m)`.
255///
256/// # Panics
257///
258/// Panics unless both inputs are finite and at least one is convex.
259pub fn min_plus_convolution_convex_smawk<T>(a: &[T], b: &[T]) -> Vec<T>
260where
261 T: Signed,
262{
263 let len = output_len(a.len(), b.len());
264 if len == 0 {
265 return Vec::new();
266 }
267 assert_finite(a);
268 assert_finite(b);
269 let (arbitrary, convex) = orient_one_convex(a, b);
270 convex_smawk(arbitrary, convex)
271}
272
273pub(super) fn convex_smawk<T>(arbitrary: &[T], convex: &[T]) -> Vec<T>
274where
275 T: Signed,
276{
277 let len = output_len(arbitrary.len(), convex.len());
278 let cost = |row: usize, col: usize| {
279 row.checked_sub(col)
280 .filter(|&index| index < convex.len())
281 .map_or(MatrixValue::Infinite, |index| {
282 MatrixValue::Finite(arbitrary[col] + convex[index])
283 })
284 };
285 let argmins = smawk(len, arbitrary.len(), &cost);
286 argmins
287 .into_iter()
288 .enumerate()
289 .map(|(row, col)| {
290 row.checked_sub(col)
291 .filter(|&index| index < convex.len())
292 .map(|index| arbitrary[col] + convex[index])
293 .expect("SMAWK minimum must be a valid convolution entry")
294 })
295 .collect()
296}More examples
crates/competitive/src/math/min_plus_convolution/concave.rs (line 30)
29 fn new(arbitrary: &'a [T], concave: &'a [T]) -> Self {
30 let output_len = output_len(arbitrary.len(), concave.len());
31 let leaf_count = 1_usize
32 .checked_shl(bit_width(output_len))
33 .expect("min-plus convolution envelope size must fit usize");
34 ConcaveEnvelope {
35 arbitrary,
36 concave,
37 leaf_count,
38 query_root: leaf_count >> bit_width(concave.len() - 1),
39 node_curves: vec![None; leaf_count],
40 result: vec![T::maximum(); output_len],
41 }
42 }
43
44 #[inline]
45 fn value(&self, curve: usize, output: usize) -> T {
46 self.arbitrary[curve] + self.concave[output - curve]
47 }
48
49 #[inline]
50 fn query(&mut self, output: usize) {
51 let mut best = self.result[output];
52 let mut node = (output + self.leaf_count) >> 1;
53 while node >= self.query_root {
54 if let Some(curve) = self.node_curves[node] {
55 best = best.min(self.value(curve, output));
56 }
57 node >>= 1;
58 }
59 self.result[output] = best;
60 }
61
62 #[inline]
63 fn insert_from_left(&mut self, left: usize) {
64 let mut right = left + self.concave.len();
65 let block = 1_usize << (left ^ right).ilog2();
66 right &= !(block - 1);
67 let mut depth = bit_width(right - left - 1);
68 let mut node = (self.leaf_count + left) >> depth;
69 let mut pending = (!self.arbitrary[left].is_maximum()).then_some(left);
70 while depth != 0 {
71 let Some(curve) = pending else {
72 break;
73 };
74 depth -= 1;
75 let middle = ((node << 1 | 1) << depth) - self.leaf_count - 1;
76 if middle < left {
77 node = node << 1 | 1;
78 } else if self.node_curves[node]
79 .is_some_and(|old| self.value(old, middle) < self.value(curve, middle))
80 {
81 node <<= 1;
82 } else {
83 std::mem::swap(&mut self.node_curves[node], &mut pending);
84 node = node << 1 | 1;
85 }
86 }
87 if let Some(curve) = pending {
88 let output = node - self.leaf_count;
89 self.result[output] = self.result[output].min(self.value(curve, output));
90 }
91 }
92
93 #[inline]
94 fn insert_from_right(&mut self, right: usize) {
95 let curve = right - self.concave.len();
96 let block = 1_usize << (curve ^ right).ilog2();
97 let left = right & !(block - 1);
98 if left == right {
99 return;
100 }
101 let mut depth = bit_width(right - left - 1);
102 let mut node = (self.leaf_count + left) >> depth;
103 let mut pending = (!self.arbitrary[curve].is_maximum()).then_some(curve);
104 while depth != 0 {
105 let Some(curve) = pending else {
106 break;
107 };
108 depth -= 1;
109 let middle = ((node << 1 | 1) << depth) - self.leaf_count;
110 if middle >= right {
111 node <<= 1;
112 } else if self.node_curves[node]
113 .is_some_and(|old| self.value(old, middle) < self.value(curve, middle))
114 {
115 node = node << 1 | 1;
116 } else {
117 std::mem::swap(&mut self.node_curves[node], &mut pending);
118 node <<= 1;
119 }
120 }
121 if let Some(curve) = pending {
122 let output = node - self.leaf_count;
123 self.result[output] = self.result[output].min(self.value(curve, output));
124 }
125 }
126
127 fn convolve(mut self) -> Vec<T> {
128 // Curve i is valid on [i, i + concave.len()). The two passes insert
129 // opposite sides of each validity interval into the segment envelope.
130 for left in 0..self.arbitrary.len() {
131 self.insert_from_left(left);
132 self.query(left);
133 }
134 for output in self.arbitrary.len()..self.result.len() {
135 self.query(output);
136 }
137
138 self.node_curves.fill(None);
139 let mut right = self.result.len();
140 while right >= self.concave.len() {
141 self.insert_from_right(right);
142 right -= 1;
143 self.query(right);
144 }
145 for output in 0..self.concave.len() {
146 self.query(output);
147 }
148 self.result
149 }
150}
151
152/// Computes convolution when one finite input is concave using offline envelopes.
153///
154/// The running time is `O((n + m) log(n + m))`. The arbitrary input may
155/// contain `T::maximum()`.
156///
157/// # Panics
158///
159/// Panics unless at least one input is finite and concave, or if the
160/// interval-tree size cannot be represented.
161pub fn min_plus_convolution_concave_envelope<T>(a: &[T], b: &[T]) -> Vec<T>
162where
163 T: Signed,
164{
165 let len = output_len(a.len(), b.len());
166 if len == 0 {
167 return Vec::new();
168 }
169 let a_is_concave = !a.iter().any(T::is_maximum) && is_concave(a);
170 let b_is_concave = !b.iter().any(T::is_maximum) && is_concave(b);
171 let (arbitrary, concave) = if b_is_concave {
172 (a, b)
173 } else if a_is_concave {
174 (b, a)
175 } else {
176 panic!("at least one min-plus convolution input must be finite and concave")
177 };
178 concave_envelope(arbitrary, concave)
179}
180
181pub(super) fn concave_envelope<T>(arbitrary: &[T], concave: &[T]) -> Vec<T>
182where
183 T: Signed,
184{
185 if concave.len() == 1 {
186 return arbitrary
187 .iter()
188 .map(|&value| {
189 if value.is_maximum() {
190 T::maximum()
191 } else {
192 value + concave[0]
193 }
194 })
195 .collect();
196 }
197 if arbitrary.len() == 1 {
198 return if arbitrary[0].is_maximum() {
199 vec![T::maximum(); concave.len()]
200 } else {
201 concave.iter().map(|&value| arbitrary[0] + value).collect()
202 };
203 }
204
205 ConcaveEnvelope::new(arbitrary, concave).convolve()
206}
207
208/// Computes convolution of two concave inputs from antidiagonal endpoints.
209///
210/// The running time is `O(n + m)`.
211///
212/// # Panics
213///
214/// Panics unless both inputs are finite and concave.
215pub fn min_plus_convolution_concave_both<T>(a: &[T], b: &[T]) -> Vec<T>
216where
217 T: Signed,
218{
219 let len = output_len(a.len(), b.len());
220 if len == 0 {
221 return Vec::new();
222 }
223 assert_finite(a);
224 assert_finite(b);
225 assert!(
226 is_concave(a) && is_concave(b),
227 "both inputs must be concave"
228 );
229 concave_both(a, b)
230}
231
232pub(super) fn concave_both<T>(a: &[T], b: &[T]) -> Vec<T>
233where
234 T: Signed,
235{
236 let len = output_len(a.len(), b.len());
237 let mut result = Vec::with_capacity(len);
238 for output in 0..len {
239 let first = output.saturating_sub(b.len() - 1);
240 let last = output.min(a.len() - 1);
241 result.push((a[first] + b[output - first]).min(a[last] + b[output - last]));
242 }
243 result
244}crates/competitive/src/math/min_plus_convolution/piecewise_linear.rs (line 131)
127pub fn min_plus_convolution_linear<T>(a: &[T], b: &[T]) -> Vec<T>
128where
129 T: Signed + TryFrom<usize>,
130{
131 let len = output_len(a.len(), b.len());
132 if len == 0 {
133 return Vec::new();
134 }
135 let a_piece = finite_pieces(a).filter(|pieces| pieces.len() == 1);
136 let b_piece = finite_pieces(b).filter(|pieces| pieces.len() == 1);
137 let (arbitrary, piece) = if let Some(pieces) = b_piece {
138 (a, pieces[0])
139 } else if let Some(pieces) = a_piece {
140 (b, pieces[0])
141 } else {
142 panic!("at least one min-plus convolution input must be finite and linear")
143 };
144 convolve_pieces(arbitrary, std::iter::once(piece), len)
145}
146
147pub(super) fn linear<T>(arbitrary: &[T], structured: &[T]) -> Vec<T>
148where
149 T: Signed + TryFrom<usize>,
150{
151 let len = output_len(arbitrary.len(), structured.len());
152 convolve_pieces(arbitrary, pieces(structured), len)
153}
154
155/// Computes convolution using the input with fewer maximal linear pieces.
156///
157/// If that input has `p` pieces, the running time is `O(p * (n + m))`.
158///
159/// # Panics
160///
161/// Panics unless at least one input is finite, or an index cannot be
162/// represented by `T`.
163pub fn min_plus_convolution_piecewise_linear<T>(a: &[T], b: &[T]) -> Vec<T>
164where
165 T: Signed + TryFrom<usize>,
166{
167 let len = output_len(a.len(), b.len());
168 if len == 0 {
169 return Vec::new();
170 }
171 let a_pieces = finite_pieces(a);
172 let b_pieces = finite_pieces(b);
173 let (arbitrary, structured) = match (a_pieces, b_pieces) {
174 (Some(a_pieces), Some(b_pieces)) if a_pieces.len() < b_pieces.len() => (b, a_pieces),
175 (Some(_), Some(b_pieces)) => (a, b_pieces),
176 (Some(a_pieces), None) => (b, a_pieces),
177 (None, Some(b_pieces)) => (a, b_pieces),
178 (None, None) => {
179 panic!("at least one min-plus convolution input must be finite")
180 }
181 };
182 convolve_pieces(arbitrary, structured, len)
183}
184
185pub(super) fn piecewise_linear<T>(arbitrary: &[T], structured: &[T]) -> Vec<T>
186where
187 T: Signed + TryFrom<usize>,
188{
189 let len = output_len(arbitrary.len(), structured.len());
190 convolve_pieces(arbitrary, pieces(structured), len)
191}crates/competitive/src/math/min_plus_convolution/monotone.rs (line 28)
24pub fn min_plus_convolution_monotone_runs<T>(a: &[T], b: &[T]) -> Vec<T>
25where
26 T: Signed,
27{
28 let len = output_len(a.len(), b.len());
29 if len == 0 {
30 return Vec::new();
31 }
32 assert_finite(a);
33 assert_finite(b);
34 let increasing = if a.windows(2).all(|window| window[0] >= window[1])
35 && b.windows(2).all(|window| window[0] >= window[1])
36 {
37 false
38 } else if a.windows(2).all(|window| window[0] <= window[1])
39 && b.windows(2).all(|window| window[0] <= window[1])
40 {
41 true
42 } else {
43 panic!("both inputs must be monotone in the same direction")
44 };
45 monotone_runs(a, b, increasing)
46}
47
48pub(super) fn monotone_runs<T>(a: &[T], b: &[T], increasing: bool) -> Vec<T>
49where
50 T: Signed,
51{
52 monotone_runs_from_entries(
53 &run_entries(a),
54 &run_entries(b),
55 a.len(),
56 b.len(),
57 increasing,
58 )
59}
60
61pub(super) fn monotone_runs_from_entries<T>(
62 a_runs: &[(usize, T)],
63 b_runs: &[(usize, T)],
64 a_len: usize,
65 b_len: usize,
66 increasing: bool,
67) -> Vec<T>
68where
69 T: Signed,
70{
71 let normalize = |runs: &[(usize, T)], len: usize| {
72 if increasing {
73 runs.iter()
74 .enumerate()
75 .rev()
76 .map(|(index, &(_, value))| {
77 (
78 len - runs.get(index + 1).map_or(len, |&(start, _)| start),
79 value,
80 )
81 })
82 .collect()
83 } else {
84 runs.to_vec()
85 }
86 };
87 let a_runs = normalize(a_runs, a_len);
88 let b_runs = normalize(b_runs, b_len);
89 let len = output_len(a_len, b_len);
90 let mut result = vec![T::maximum(); len];
91 for &(left_start, left_value) in &a_runs {
92 for &(right_start, right_value) in &b_runs {
93 let output = left_start + right_start;
94 result[output] = result[output].min(left_value + right_value);
95 }
96 }
97 for output in 1..len {
98 result[output] = result[output].min(result[output - 1]);
99 }
100 if increasing {
101 result.reverse();
102 }
103 result
104}crates/competitive/src/math/min_plus_convolution/mod.rs (line 60)
56pub fn min_plus_convolution_naive<T>(a: &[T], b: &[T]) -> Vec<T>
57where
58 T: Signed,
59{
60 let len = output_len(a.len(), b.len());
61 if len == 0 {
62 return Vec::new();
63 }
64 let (outer, inner) = if a.len() <= b.len() { (a, b) } else { (b, a) };
65 let inner_is_finite = !inner.iter().any(T::is_maximum);
66 let mut result = vec![T::maximum(); len];
67 for (index, &left) in outer.iter().enumerate() {
68 if left.is_maximum() {
69 continue;
70 }
71 let output = &mut result[index..index + inner.len()];
72 if inner_is_finite {
73 for (slot, &right) in output.iter_mut().zip(inner) {
74 *slot = (*slot).min(left + right);
75 }
76 } else {
77 for (slot, &right) in output.iter_mut().zip(inner) {
78 if !right.is_maximum() {
79 *slot = (*slot).min(left + right);
80 }
81 }
82 }
83 }
84 result
85}
86
87/// Computes min-plus convolution by enumerating finite input pairs only.
88///
89/// If the inputs have `s_a` and `s_b` finite values, the running time is
90/// `O(s_a * s_b + n + m)`.
91///
92/// # Panics
93///
94/// Panics if the output length does not fit [`usize`]. Arithmetic overflow is
95/// the caller's responsibility.
96pub fn min_plus_convolution_sparse<T>(a: &[T], b: &[T]) -> Vec<T>
97where
98 T: Signed,
99{
100 let len = output_len(a.len(), b.len());
101 if len == 0 {
102 return Vec::new();
103 }
104 let a: Vec<_> = a
105 .iter()
106 .copied()
107 .enumerate()
108 .filter(|(_, value)| !value.is_maximum())
109 .collect();
110 let b: Vec<_> = b
111 .iter()
112 .copied()
113 .enumerate()
114 .filter(|(_, value)| !value.is_maximum())
115 .collect();
116 sparse(a.iter().copied(), b.iter().copied(), len)
117}
118
119fn sparse<T>(
120 a: impl IntoIterator<Item = (usize, T)>,
121 b: impl IntoIterator<Item = (usize, T)> + Clone,
122 len: usize,
123) -> Vec<T>
124where
125 T: Signed,
126{
127 let mut result = vec![T::maximum(); len];
128 for (i, left) in a {
129 for (j, right) in b.clone() {
130 result[i + j] = result[i + j].min(left + right);
131 }
132 }
133 result
134}
135
136const MAX_NTT_SIZE: usize = 1 << 23;
137
138#[derive(Clone, Copy, Debug)]
139struct BoundedRequirements<T> {
140 a_min: T,
141 b_min: T,
142 base: usize,
143 transform_len: usize,
144}
145
146fn finite_extrema<T>(values: &[T]) -> Option<(T, T)>
147where
148 T: Signed,
149{
150 let mut finite = values.iter().copied().filter(|value| !value.is_maximum());
151 let first = finite.next()?;
152 Some(finite.fold((first, first), |(minimum, maximum), value| {
153 (minimum.min(value), maximum.max(value))
154 }))
155}
156
157fn bounded_transform_len(a_len: usize, b_len: usize, base: usize) -> Option<usize> {
158 let left_len = a_len.checked_mul(base)?;
159 let right_len = b_len.checked_mul(base)?;
160 let coefficient_len = left_len
161 .checked_add(right_len)
162 .and_then(|len| len.checked_sub(1))?;
163 let transform_len = coefficient_len.checked_next_power_of_two()?;
164 (transform_len <= MAX_NTT_SIZE).then_some(transform_len)
165}
166
167fn bounded_requirements_from_extrema<T>(
168 a_len: usize,
169 b_len: usize,
170 (a_min, a_max): (T, T),
171 (b_min, b_max): (T, T),
172) -> Option<BoundedRequirements<T>>
173where
174 T: Signed,
175 T::Unsigned: TryInto<usize>,
176{
177 let a_span = a_max.abs_diff(a_min).try_into().ok()?;
178 let b_span = b_max.abs_diff(b_min).try_into().ok()?;
179 let base = a_span
180 .checked_add(b_span)
181 .and_then(|span| span.checked_add(1))?;
182 let transform_len = bounded_transform_len(a_len, b_len, base)?;
183 Some(BoundedRequirements {
184 a_min,
185 b_min,
186 base,
187 transform_len,
188 })
189}
190
191/// Computes exact min-plus convolution for small integer value spans using NTT.
192///
193/// # Panics
194///
195/// Panics if the encoded range cannot be represented or requires a transform
196/// longer than `2^23`. Arithmetic overflow is the caller's responsibility.
197pub fn min_plus_convolution_bounded_ntt<T>(a: &[T], b: &[T]) -> Vec<T>
198where
199 T: Signed + TryFrom<usize>,
200 T::Unsigned: TryInto<usize>,
201{
202 let output_len = output_len(a.len(), b.len());
203 if output_len == 0 {
204 return Vec::new();
205 }
206 let (Some(a_extrema), Some(b_extrema)) = (finite_extrema(a), finite_extrema(b)) else {
207 return vec![T::maximum(); output_len];
208 };
209 let requirements = bounded_requirements_from_extrema(a.len(), b.len(), a_extrema, b_extrema)
210 .expect("bounded min-plus convolution encoding must fit the 2^23 NTT limit");
211 let mut left = vec![MInt998244353::from(0_u32); a.len() * requirements.base];
212 let mut right = vec![MInt998244353::from(0_u32); b.len() * requirements.base];
213 for (index, &value) in a.iter().enumerate() {
214 if !value.is_maximum() {
215 let normalized: usize = value
216 .abs_diff(requirements.a_min)
217 .try_into()
218 .ok()
219 .expect("bounded min-plus convolution value span must fit usize");
220 left[index * requirements.base + normalized] = MInt998244353::from(1_u32);
221 }
222 }
223 for (index, &value) in b.iter().enumerate() {
224 if !value.is_maximum() {
225 let normalized: usize = value
226 .abs_diff(requirements.b_min)
227 .try_into()
228 .ok()
229 .expect("bounded min-plus convolution value span must fit usize");
230 right[index * requirements.base + normalized] = MInt998244353::from(1_u32);
231 }
232 }
233 let coefficients = Convolve998244353::convolve(left, right);
234 let encoded_len = output_len
235 .checked_mul(requirements.base)
236 .expect("bounded min-plus convolution encoded length must fit usize");
237 let mut result = Vec::with_capacity(output_len);
238 for chunk in coefficients[..encoded_len].chunks_exact(requirements.base) {
239 let value = if let Some(normalized) = chunk.iter().position(|&value| u32::from(value) != 0)
240 {
241 requirements.a_min
242 + requirements.b_min
243 + T::try_from(normalized)
244 .ok()
245 .expect("bounded min-plus convolution value must fit the output type")
246 } else {
247 T::maximum()
248 };
249 result.push(value);
250 }
251 result
252}crates/competitive/src/math/min_plus_convolution/near_convex.rs (line 75)
65pub fn min_plus_convolution_near_convex_scan<T>(
66 a: &[T],
67 b: &[T],
68 convex_a: &[T],
69 convex_b: &[T],
70 delta: T,
71) -> Vec<T>
72where
73 T: Signed,
74{
75 let len = output_len(a.len(), b.len());
76 if len == 0 {
77 return Vec::new();
78 }
79 validate_witness(a, convex_a, delta);
80 validate_witness(b, convex_b, delta);
81 let (convex_output, witnesses) = convex_convolution_witnesses(convex_a, convex_b);
82 let tolerance = delta + delta;
83 let relevant = |output: usize, i: usize| {
84 convex_a[i] + convex_b[output - i] <= convex_output[output] + tolerance
85 };
86 let mut result = Vec::with_capacity(len);
87 for output in 0..len {
88 let first = output.saturating_sub(b.len() - 1);
89 let last = output.min(a.len() - 1);
90 let witness = witnesses[output];
91 let mut low = first;
92 let mut high = witness;
93 while low < high {
94 let middle = low + (high - low) / 2;
95 if relevant(output, middle) {
96 high = middle;
97 } else {
98 low = middle + 1;
99 }
100 }
101 let first_relevant = low;
102 low = witness;
103 high = last;
104 while low < high {
105 let middle = low + (high - low).div_ceil(2);
106 if relevant(output, middle) {
107 low = middle;
108 } else {
109 high = middle - 1;
110 }
111 }
112 let mut best = T::maximum();
113 for i in first_relevant..=low {
114 best = best.min(a[i] + b[output - i]);
115 }
116 result.push(best);
117 }
118 result
119}Additional examples can be found in: