cp-library

C++ Library for Competitive Programming

View the Project on GitHub emthrm/cp-library

:heavy_check_mark: 添え字 gcd での畳み込み
(include/emthrm/math/convolution/gcd_convolution.hpp)

$C_k = \sum_{k = i \circ j} A_i B_j$ を求める。ただし $\circ$ は二項演算である。

添え字 xor での畳み込みには『高速ウォルシュ・アダマール変換 (fast Walsh-Hadamard transform)』を用いる。

時間計算量

$O(N\log{N})$

仕様

添え字 and での畳み込み

名前 戻り値
template <typename T>
std::vector<T> and_convolution(std::vector<T> a, std::vector<T> b, const T id = 0);
$A, B$ に対する添え字 and での畳み込み

添え字 or での畳み込み

名前 戻り値
template <typename T>
std::vector<T> or_convolution(std::vector<T> a, std::vector<T> b, const T id = 0);
$A, B$ に対する添え字 or での畳み込み

添え字 xor での畳み込み

名前 戻り値
template <typename T>
std::vector<T> xor_convolution(std::vector<T> a, std::vector<T> b, const T id = 0);
$A, B$ に対する添え字 xor での畳み込み

添え字 gcd での畳み込み

名前 戻り値
template <typename T>
std::vector<T> gcd_convolution(std::vector<T> a, std::vector<T> b);
$A, B$ に対する添え字 gcd での畳み込み

添え字 lcm での畳み込み

名前 戻り値
template <typename T>
std::vector<T> lcm_convolution(std::vector<T> a, std::vector<T> b, const int n = -1);
$A, B$ に対する添え字 lcm での畳み込み

参考文献

高速ウォルシュ・アダマール変換

添え字 gcd での畳み込み

添え字 lcm での畳み込み

TODO

Submissons

Verified with

Code

#ifndef EMTHRM_MATH_CONVOLUTION_GCD_CONVOLUTION_HPP_
#define EMTHRM_MATH_CONVOLUTION_GCD_CONVOLUTION_HPP_

#include <algorithm>
#include <vector>

namespace emthrm {

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());
  const auto transform = [n](std::vector<T>* v) -> void {
    for (int i = 1; i < n; ++i) {
      for (int j = i << 1; j < n; j += i) {
        (*v)[i] += (*v)[j];
      }
    }
  };
  a.resize(n, 0);
  transform(&a);
  b.resize(n, 0);
  transform(&b);
  for (int i = 1; i < n; ++i) {
    a[i] *= b[i];
  }
  for (int i = n - 1; i >= 1; --i) {
    for (int j = i << 1; j < n; j += i) {
      a[i] -= a[j];
    }
  }
  return a;
}

}  // namespace emthrm

#endif  // EMTHRM_MATH_CONVOLUTION_GCD_CONVOLUTION_HPP_
#line 1 "include/emthrm/math/convolution/gcd_convolution.hpp"



#include <algorithm>
#include <vector>

namespace emthrm {

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());
  const auto transform = [n](std::vector<T>* v) -> void {
    for (int i = 1; i < n; ++i) {
      for (int j = i << 1; j < n; j += i) {
        (*v)[i] += (*v)[j];
      }
    }
  };
  a.resize(n, 0);
  transform(&a);
  b.resize(n, 0);
  transform(&b);
  for (int i = 1; i < n; ++i) {
    a[i] *= b[i];
  }
  for (int i = n - 1; i >= 1; --i) {
    for (int j = i << 1; j < n; j += i) {
      a[i] -= a[j];
    }
  }
  return a;
}

}  // namespace emthrm
Back to top page