Skip to the content.

:heavy_check_mark: 約数・倍数変換
(number-theory/divisor-multiple-transform.hpp)

約数・倍数変換

長さ $\red{N+1}$ の vector $(a_0,a_1,\dots,a_N)$ を受け取る.

(約数/倍数)(ゼータ/メビウス)変換では次を満たす vector $(b_0,b_1,\dots,b_N)$ を返す.

いずれも時間計算量は $O(N\log\log N)$.

GCD/LCM 畳み込み

代表的な使用例.

ゼータ変換し,各点積をとってメビウス変換すればよい.

Required by

Verified with

Code

#pragma once

template <class T>
void DivisorZetaTransform(vector<T>& a) {
  if (a.empty()) return;
  int n = a.size();
  vector<bool> sieve(n, true);
  for (int p = 2; p < n; p++) {
    if (sieve[p]) {
      for (int k = 1; k * p < n; k++) {
        sieve[k * p] = false;
        a[k * p] += a[k];
      }
    }
  }
}

template <class T>
void DivisorMobiusTransform(vector<T>& a) {
  if (a.empty()) return;
  int n = a.size();
  vector<bool> sieve(n, true);
  for (int p = 2; p < n; p++) {
    if (sieve[p]) {
      for (int k = (n - 1) / p; k > 0; k--) {
        sieve[k * p] = false;
        a[k * p] -= a[k];
      }
    }
  }
}

template <class T>
void MultipleZetaTransform(vector<T>& a) {
  if (a.empty()) return;
  int n = a.size();
  vector<bool> sieve(n, true);
  for (int p = 2; p < n; p++) {
    if (sieve[p]) {
      for (int k = (n - 1) / p; k > 0; k--) {
        sieve[k * p] = false;
        a[k] += a[k * p];
      }
    }
  }
}

template <class T>
void MultipleMobiusTransform(vector<T>& a) {
  if (a.empty()) return;
  int n = a.size();
  vector<bool> sieve(n, true);
  for (int p = 2; p < n; p++) {
    if (sieve[p]) {
      for (int k = 1; k * p < n; k++) {
        sieve[k * p] = false;
        a[k] -= a[k * p];
      }
    }
  }
}

/**
 * @brief 約数・倍数変換
 * @docs docs/number-theory/divisor-multiple-transform.md
 */
#line 2 "number-theory/divisor-multiple-transform.hpp"

template <class T>
void DivisorZetaTransform(vector<T>& a) {
  if (a.empty()) return;
  int n = a.size();
  vector<bool> sieve(n, true);
  for (int p = 2; p < n; p++) {
    if (sieve[p]) {
      for (int k = 1; k * p < n; k++) {
        sieve[k * p] = false;
        a[k * p] += a[k];
      }
    }
  }
}

template <class T>
void DivisorMobiusTransform(vector<T>& a) {
  if (a.empty()) return;
  int n = a.size();
  vector<bool> sieve(n, true);
  for (int p = 2; p < n; p++) {
    if (sieve[p]) {
      for (int k = (n - 1) / p; k > 0; k--) {
        sieve[k * p] = false;
        a[k * p] -= a[k];
      }
    }
  }
}

template <class T>
void MultipleZetaTransform(vector<T>& a) {
  if (a.empty()) return;
  int n = a.size();
  vector<bool> sieve(n, true);
  for (int p = 2; p < n; p++) {
    if (sieve[p]) {
      for (int k = (n - 1) / p; k > 0; k--) {
        sieve[k * p] = false;
        a[k] += a[k * p];
      }
    }
  }
}

template <class T>
void MultipleMobiusTransform(vector<T>& a) {
  if (a.empty()) return;
  int n = a.size();
  vector<bool> sieve(n, true);
  for (int p = 2; p < n; p++) {
    if (sieve[p]) {
      for (int k = 1; k * p < n; k++) {
        sieve[k * p] = false;
        a[k] -= a[k * p];
      }
    }
  }
}

/**
 * @brief 約数・倍数変換
 * @docs docs/number-theory/divisor-multiple-transform.md
 */
Back to top page