sotanishy's competitive programming library

sotanishy's code snippets for competitive programming

View the Project on GitHub sotanishy/cp-library-cpp

:heavy_check_mark: GCD/LCM Convolution
(convolution/gcd_lcm_convolution.hpp)

Depends on

Verified with

Code

#pragma once
#include <vector>

#include "divisor_zeta_moebius_transform.hpp"

/**
 * @brief GCD/LCM Convolution
 */

template <typename T>
std::vector<T> gcd_convolution(std::vector<T> a, std::vector<T> b) {
    const int n = std::max(a.size(), b.size());
    a.resize(n);
    b.resize(n);
    multiple_fzt(a);
    multiple_fzt(b);
    for (int i = 0; i < n; ++i) a[i] *= b[i];
    multiple_fmt(a);
    return a;
}

template <typename T>
std::vector<T> lcm_convolution(std::vector<T> a, std::vector<T> b) {
    const int n = std::max(a.size(), b.size());
    a.resize(n);
    b.resize(n);
    divisor_fzt(a);
    divisor_fzt(b);
    for (int i = 0; i < n; ++i) a[i] *= b[i];
    divisor_fmt(a);
    return a;
}
#line 2 "convolution/gcd_lcm_convolution.hpp"
#include <vector>

#line 3 "convolution/divisor_zeta_moebius_transform.hpp"

template <typename T>
void divisor_fzt(std::vector<T>& a) {
    const int n = a.size();
    std::vector<bool> sieve(n, true);
    for (int p = 2; p < n; ++p) {
        if (!sieve[p]) continue;
        for (int k = 1; k * p < n; ++k) {
            sieve[k * p] = false;
            a[k * p] += a[k];
        }
    }
}

template <typename T>
void divisor_fmt(std::vector<T>& a) {
    const int n = a.size();
    std::vector<bool> sieve(n, true);
    for (int p = 2; p < n; ++p) {
        if (!sieve[p]) continue;
        for (int k = (n - 1) / p; k > 0; --k) {
            sieve[k * p] = false;
            a[k * p] -= a[k];
        }
    }
}

template <typename T>
void multiple_fzt(std::vector<T>& a) {
    const int n = a.size();
    std::vector<bool> sieve(n, true);
    for (int p = 2; p < n; ++p) {
        if (!sieve[p]) continue;
        for (int k = (n - 1) / p; k > 0; --k) {
            sieve[k * p] = false;
            a[k] += a[k * p];
        }
    }
}

template <typename T>
void multiple_fmt(std::vector<T>& a) {
    const int n = a.size();
    std::vector<bool> sieve(n, true);
    for (int p = 2; p < n; ++p) {
        if (!sieve[p]) continue;
        for (int k = 1; k * p < n; ++k) {
            sieve[k * p] = false;
            a[k] -= a[k * p];
        }
    }
}
#line 5 "convolution/gcd_lcm_convolution.hpp"

/**
 * @brief GCD/LCM Convolution
 */

template <typename T>
std::vector<T> gcd_convolution(std::vector<T> a, std::vector<T> b) {
    const int n = std::max(a.size(), b.size());
    a.resize(n);
    b.resize(n);
    multiple_fzt(a);
    multiple_fzt(b);
    for (int i = 0; i < n; ++i) a[i] *= b[i];
    multiple_fmt(a);
    return a;
}

template <typename T>
std::vector<T> lcm_convolution(std::vector<T> a, std::vector<T> b) {
    const int n = std::max(a.size(), b.size());
    a.resize(n);
    b.resize(n);
    divisor_fzt(a);
    divisor_fzt(b);
    for (int i = 0; i < n; ++i) a[i] *= b[i];
    divisor_fmt(a);
    return a;
}
Back to top page