C++ Library for Competitive Programming
#include "emthrm/math/convolution/lcm_convolution.hpp"
$C_k = \sum_{k = i \circ j} A_i B_j$ を求める。ただし $\circ$ は二項演算である。
添え字 xor での畳み込みには『高速ウォルシュ・アダマール変換 (fast Walsh-Hadamard transform)』を用いる。
$O(N\log{N})$
名前 | 戻り値 |
---|---|
template <typename T> std::vector<T> and_convolution(std::vector<T> a, std::vector<T> b, const T id = 0);
|
$A, B$ に対する添え字 and での畳み込み |
名前 | 戻り値 |
---|---|
template <typename T> std::vector<T> or_convolution(std::vector<T> a, std::vector<T> b, const T id = 0);
|
$A, B$ に対する添え字 or での畳み込み |
名前 | 戻り値 |
---|---|
template <typename T> std::vector<T> xor_convolution(std::vector<T> a, std::vector<T> b, const T id = 0);
|
$A, B$ に対する添え字 xor での畳み込み |
名前 | 戻り値 |
---|---|
template <typename T> std::vector<T> gcd_convolution(std::vector<T> a, std::vector<T> b);
|
$A, B$ に対する添え字 gcd での畳み込み |
名前 | 戻り値 |
---|---|
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 での畳み込み
#ifndef EMTHRM_MATH_CONVOLUTION_LCM_CONVOLUTION_HPP_
#define EMTHRM_MATH_CONVOLUTION_LCM_CONVOLUTION_HPP_
#include <vector>
namespace emthrm {
template <typename T>
std::vector<T> lcm_convolution(std::vector<T> a, std::vector<T> b,
const int n = -1) {
if (n == -1) return lcm_convolution(a, b, (a.size() - 1) * (b.size() - 1));
a.resize(n + 1, 0);
b.resize(n + 1, 0);
const auto transform = [n](std::vector<T>* v) -> void {
for (int i = n; i >= 1; --i) {
for (int j = i << 1; j <= n; j += i) {
(*v)[j] += (*v)[i];
}
}
};
transform(&a);
transform(&b);
for (int i = 1; i <= n; ++i) {
a[i] *= b[i];
}
for (int i = 1; i <= n; ++i) {
for (int j = i << 1; j <= n; j += i) {
a[j] -= a[i];
}
}
return a;
}
} // namespace emthrm
#endif // EMTHRM_MATH_CONVOLUTION_LCM_CONVOLUTION_HPP_
#line 1 "include/emthrm/math/convolution/lcm_convolution.hpp"
#include <vector>
namespace emthrm {
template <typename T>
std::vector<T> lcm_convolution(std::vector<T> a, std::vector<T> b,
const int n = -1) {
if (n == -1) return lcm_convolution(a, b, (a.size() - 1) * (b.size() - 1));
a.resize(n + 1, 0);
b.resize(n + 1, 0);
const auto transform = [n](std::vector<T>* v) -> void {
for (int i = n; i >= 1; --i) {
for (int j = i << 1; j <= n; j += i) {
(*v)[j] += (*v)[i];
}
}
};
transform(&a);
transform(&b);
for (int i = 1; i <= n; ++i) {
a[i] *= b[i];
}
for (int i = 1; i <= n; ++i) {
for (int j = i << 1; j <= n; j += i) {
a[j] -= a[i];
}
}
return a;
}
} // namespace emthrm