From c0bcddb1704b4ccc488aa153a519385e76e72906 Mon Sep 17 00:00:00 2001 From: enwask Date: Fri, 10 Oct 2025 12:38:35 -0400 Subject: [PATCH 1/2] Add GCD+LCM convolution --- content/numerical/GcdConvolution.h | 26 ++++++++++++++++++++++++++ content/numerical/LcmConvolution.h | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 content/numerical/GcdConvolution.h create mode 100644 content/numerical/LcmConvolution.h diff --git a/content/numerical/GcdConvolution.h b/content/numerical/GcdConvolution.h new file mode 100644 index 000000000..9c4c94e1b --- /dev/null +++ b/content/numerical/GcdConvolution.h @@ -0,0 +1,26 @@ +/** + * Author: Luke Videckis + * Date: 2024-02-20 + * Source: https://github.com/programming-team-code/programming_team_code/blob/main/convolution/gcd_convolution.hpp + * Description: Returns $\displaystyle c[k] = \sum_{gcd(i,j)=k} a[i] \cdot b[j]$. + * Time: O(n \log n) + * Status: unknown + */ +#pragma once + +const int mod = 998'244'353; +vector gcd_convolution(const vector& a, + const vector& b) { + int n = ssize(a); + vector c(n); + for (int g = n - 1; g >= 1; g--) { + int64_t sum_a = 0, sum_b = 0; + for (int i = g; i < n; i += g) { + sum_a += a[i], sum_b += b[i]; + if ((c[g] -= c[i]) < 0) c[g] += mod; + } + sum_a %= mod, sum_b %= mod; + c[g] = (c[g] + sum_a * sum_b) % mod; + } + return c; +} diff --git a/content/numerical/LcmConvolution.h b/content/numerical/LcmConvolution.h new file mode 100644 index 000000000..3f4ede5f3 --- /dev/null +++ b/content/numerical/LcmConvolution.h @@ -0,0 +1,26 @@ +/** + * Author: Luke Videckis + * Date: 2024-02-20 + * Source: https://github.com/programming-team-code/programming_team_code/blob/main/convolution/lcm_convolution.hpp + * Description: Returns $\displaystyle c[k] = \sum_{lcm(i,j)=k} a[i] \cdot b[j]$. + * Time: O(n \log n) + * Status: unknown + */ +#pragma once + +const int mod = 998'244'353; +vector lcm_convolution(const vector& a, + const vector& b) { + int n = ssize(a); + vector sum_a(n), sum_b(n); + vector c(n); + for (int i = 1; i < n; i++) { + for (int j = i; j < n; j += i) + sum_a[j] += a[i], sum_b[j] += b[i]; + sum_a[i] %= mod, sum_b[i] %= mod; + c[i] = (c[i] + sum_a[i] * sum_b[i]) % mod; + for (int j = i + i; j < n; j += i) + if ((c[j] -= c[i]) < 0) c[j] += mod; + } + return c; +} From 49c3f58e981d3ed8b43200f8b8f92efec9a62519 Mon Sep 17 00:00:00 2001 From: enwask Date: Fri, 10 Oct 2025 12:46:42 -0400 Subject: [PATCH 2/2] Add GCD+LCM conv to hackpack chapter --- content/numerical/chapter.tex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/numerical/chapter.tex b/content/numerical/chapter.tex index afefd94cd..1dbc45be1 100644 --- a/content/numerical/chapter.tex +++ b/content/numerical/chapter.tex @@ -31,3 +31,5 @@ \section{Fourier transforms} \kactlimport{FastFourierTransformMod.h} \kactlimport{NumberTheoreticTransform.h} \kactlimport{FastSubsetTransform.h} + \kactlimport{GcdConvolution.h} + \kactlimport{LcmConvolution.h}