集合冪級数の log
(set-function/log-of-set-power-series.hpp)
Depends on
Verified with
Code
#pragma once
#include <cassert>
#include <vector>
using namespace std;
#include "subset-convolution.hpp"
template <typename mint, int MAX = 21>
vector<mint> log_of_set_power_series(int n, vector<mint> h) {
assert(0 <= n && n <= MAX);
static SubsetConvolution<mint, MAX> ss;
h.resize(1 << n);
assert(h[0] == 1);
vector<mint> g{0}, inv{1};
for (int k = 1; k <= n; k++) {
auto a = ss.multiply(inv, {begin(h) + (1 << (k - 1)), begin(h) + (1 << k)});
copy(begin(a), end(a), back_inserter(g));
auto b = ss.multiply(a, inv);
for (auto& x : b) x = -x;
copy(begin(b), end(b), back_inserter(inv));
}
return g;
}
/**
* @brief 集合冪級数の log
*/
#line 2 "set-function/log-of-set-power-series.hpp"
#include <cassert>
#include <vector>
using namespace std;
#line 2 "set-function/subset-convolution.hpp"
#include <array>
#line 5 "set-function/subset-convolution.hpp"
using namespace std;
template <typename mint, int _s>
struct SubsetConvolution {
using fps = array<mint, _s + 1>;
static constexpr int s = _s;
vector<int> pc;
SubsetConvolution() : pc(1 << s) {
for (int i = 1; i < (1 << s); i++) pc[i] = pc[i - (i & -i)] + 1;
}
void add(fps& l, const fps& r, int d) {
for (int i = 0; i < d; ++i) l[i] += r[i];
}
void sub(fps& l, const fps& r, int d) {
for (int i = d; i <= s; ++i) l[i] -= r[i];
}
void zeta(vector<fps>& a) {
int n = a.size();
for (int w = 1; w < n; w *= 2) {
for (int k = 0; k < n; k += w * 2) {
for (int i = 0; i < w; ++i) {
add(a[k + w + i], a[k + i], pc[k + w + i]);
}
}
}
}
void mobius(vector<fps>& a) {
int n = a.size();
for (int w = n >> 1; w; w >>= 1) {
for (int k = 0; k < n; k += w * 2) {
for (int i = 0; i < w; ++i) {
sub(a[k + w + i], a[k + i], pc[k + w + i]);
}
}
}
}
vector<fps> lift(const vector<mint>& a) {
vector<fps> A(a.size());
for (int i = 0; i < (int)a.size(); i++) {
fill(begin(A[i]), end(A[i]), mint());
A[i][pc[i]] = a[i];
}
return A;
}
vector<mint> unlift(const vector<fps>& A) {
vector<mint> a(A.size());
for (int i = 0; i < (int)A.size(); i++) a[i] = A[i][pc[i]];
return a;
}
void prod(vector<fps>& A, const vector<fps>& B) {
int n = A.size(), d = __builtin_ctz(n);
for (int i = 0; i < n; i++) {
fps c{};
for (int j = 0; j <= d; j++) {
for (int k = 0; k <= d - j; k++) {
c[j + k] += A[i][j] * B[i][k];
}
}
A[i].swap(c);
}
}
vector<mint> multiply(const vector<mint>& a, const vector<mint>& b) {
vector<fps> A = lift(a), B = lift(b);
zeta(A), zeta(B);
prod(A, B);
mobius(A);
return unlift(A);
}
};
/**
* @brief Subset Convolution
*/
#line 8 "set-function/log-of-set-power-series.hpp"
template <typename mint, int MAX = 21>
vector<mint> log_of_set_power_series(int n, vector<mint> h) {
assert(0 <= n && n <= MAX);
static SubsetConvolution<mint, MAX> ss;
h.resize(1 << n);
assert(h[0] == 1);
vector<mint> g{0}, inv{1};
for (int k = 1; k <= n; k++) {
auto a = ss.multiply(inv, {begin(h) + (1 << (k - 1)), begin(h) + (1 << k)});
copy(begin(a), end(a), back_inserter(g));
auto b = ss.multiply(a, inv);
for (auto& x : b) x = -x;
copy(begin(b), end(b), back_inserter(inv));
}
return g;
}
/**
* @brief 集合冪級数の log
*/
Back to top page