sotanishy's competitive programming library

sotanishy's code snippets for competitive programming

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

:heavy_check_mark: Multiple/Divisor Fast Zeta/Möbius Transform
(convolution/divisor_zeta_moebius_transform.hpp)

Description

約数に関する zeta 変換は,写像 $f$ が与えられたとき,以下を満たす写像 $g$ を得る変換である.Möbius 変換は,zeta 変換の逆変換である (つまり,写像 $g$ が与えられたとき,以下を満たす写像 $f$ を得る変換である).

\[g(n) = \sum_{m | n} f(m)\]

倍数に関する変換も同様である.

約数に関する FZT/FMT を用いると,LCM convolution が高速に計算できる.

\[c_k = \sum_{\mathrm{lcm}(i,j)=k} a_i b_j\]

倍数に関する FZT/FMT を用いると,GCD convolution が高速に計算できる.

\[c_k = \sum_{\gcd(i,j)=k} a_i b_j\]

Operations

Note

畳み込み 変換 逆変換
$\max$ zeta 変換 (累積和,下位) Möbius 変換 (累積和,下位)
$\min$ zeta 変換 (累積和,上位) Möbius 変換 (累積和,上位)
$\gcd$ zeta 変換 (倍数) Möbius 変換 (倍数)
$\mathrm{lcm}$ zeta 変換 (約数) Möbius 変換 (約数)
$\mathrm{bitwise\ and}$ zeta 変換 (bit,上位) Möbius 変換 (bit,上位)
$\mathrm{bitwise\ or}$ zeta 変換 (bit,下位) Möbius 変換 (bit,下位)
$\mathrm{bitwise\ xor}$ Walsh-Hadamard 変換 逆 Walsh-Hadamard 変換
$+$ Fourier 変換,数論変換 逆 Fourier 変換,逆数論変換

Reference

Required by

Verified with

Code

#pragma once
#include <vector>

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 2 "convolution/divisor_zeta_moebius_transform.hpp"
#include <vector>

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];
        }
    }
}
Back to top page