This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub ebi-fly13/Library
#include "convolution/lcm_convolution.hpp"
長さ$N+1$ の整数列 $a$, $b$ について、 $c_k = \sum_{lcm(i, j) = k} a_i b_j$ を $O(N\log \log N)$ で計算する。
#pragma once #include "../math/divisor_transform.hpp" namespace ebi { template <class mint> std::vector<mint> lcm_convolution(const std::vector<mint> &a, const std::vector<mint> &b) { int n = a.size(); assert(a.size() == b.size()); auto ra = divisor_transform::zeta_transform(a); auto rb = divisor_transform::zeta_transform(b); for (int i = 0; i < n; i++) { ra[i] *= rb[i]; } return divisor_transform::mobius_transform(ra); } } // namespace ebi
#line 2 "convolution/lcm_convolution.hpp" #line 2 "math/divisor_transform.hpp" #include <vector> #line 2 "math/eratosthenes_sieve.hpp" #include <cassert> #include <cstdint> #line 6 "math/eratosthenes_sieve.hpp" /* reference: https://37zigen.com/sieve-eratosthenes/ */ namespace ebi { struct eratosthenes_sieve { private: using i64 = std::int_fast64_t; int n; std::vector<bool> table; public: eratosthenes_sieve(int _n) : n(_n), table(std::vector<bool>(n + 1, true)) { table[1] = false; for (i64 i = 2; i * i <= n; i++) { if (!table[i]) continue; for (i64 j = i; i * j <= n; j++) { table[i * j] = false; } } } bool is_prime(int p) { return table[p]; } std::vector<int> prime_table(int m = -1) { if (m < 0) m = n; std::vector<int> prime; for (int i = 2; i <= m; i++) { if (table[i]) prime.emplace_back(i); } return prime; } }; } // namespace ebi #line 6 "math/divisor_transform.hpp" namespace ebi { struct divisor_transform { divisor_transform() = default; template <class mint> static std::vector<mint> zeta_transform(const std::vector<mint> &f) { int n = f.size() - 1; auto F = f; if (m < n) { while (m < n) m <<= 1; eratosthenes_sieve sieve(m); primes = sieve.prime_table(); } for (const auto &p : primes) { if (n < p) break; for (int i = 1; i * p <= n; i++) F[p * i] += F[i]; } return F; } template <class mint> static std::vector<mint> mobius_transform(const std::vector<mint> &F) { int n = F.size() - 1; auto f = F; if (m < n) { while (m < n) m <<= 1; eratosthenes_sieve sieve(m); primes = sieve.prime_table(); } for (const auto &p : primes) { if (n < p) break; for (int i = n / p; i > 0; i--) f[p * i] -= f[i]; } return f; } private: static int m; static std::vector<int> primes; }; int divisor_transform::m = 4; std::vector<int> divisor_transform::primes = {2, 3}; } // namespace ebi #line 4 "convolution/lcm_convolution.hpp" namespace ebi { template <class mint> std::vector<mint> lcm_convolution(const std::vector<mint> &a, const std::vector<mint> &b) { int n = a.size(); assert(a.size() == b.size()); auto ra = divisor_transform::zeta_transform(a); auto rb = divisor_transform::zeta_transform(b); for (int i = 0; i < n; i++) { ra[i] *= rb[i]; } return divisor_transform::mobius_transform(ra); } } // namespace ebi