This documentation is automatically generated by online-judge-tools/verification-helper
#include "setfunc/sps_exp.hpp"#pragma once
#include "setfunc/subset_convolution.hpp"
// sum_i 1/i! s^i, s^i is subset-convolution
template <typename mint, int LIM>
vc<mint> sps_exp(vc<mint>& s) {
const int N = topbit(len(s));
assert(len(s) == (1 << N) && s[0] == mint(0));
vc<mint> dp(1 << N);
dp[0] = mint(1);
FOR(i, N) {
vc<mint> a = {s.begin() + (1 << i), s.begin() + (2 << i)};
vc<mint> b = {dp.begin(), dp.begin() + (1 << i)};
a = subset_convolution<mint, LIM>(a, b);
copy(all(a), dp.begin() + (1 << i));
}
return dp;
}#line 2 "setfunc/sps_exp.hpp"
#line 2 "setfunc/subset_convolution.hpp"
#line 2 "setfunc/ranked_zeta.hpp"
#line 2 "setfunc/bitwise_transform.hpp"
namespace bitwise {
enum class trans_type {
hadamard,
superset_zeta,
superset_mobius,
subset_zeta,
subset_mobius,
ranked_zeta,
ranked_mobius
};
template <typename ARR>
inline void ranked_add(ARR& a, const ARR& b) {
for (int d = 0; d < int(a.size()); ++d) a[d] += b[d];
}
template <typename ARR>
inline void ranked_sub(ARR& a, const ARR& b) {
for (int d = 0; d < int(a.size()); ++d) a[d] -= b[d];
}
template <trans_type type, int N, typename T>
inline void bitwise_transform_fixed(T* a) {
static_assert(N >= 1 && (N & (N - 1)) == 0);
if constexpr (N == 1) {
return;
} else {
constexpr int H = N / 2;
bitwise_transform_fixed<type, H>(a);
bitwise_transform_fixed<type, H>(a + H);
if constexpr (type == trans_type::hadamard) {
for (int i = 0; i < H; ++i) {
auto x = a[i], y = a[H + i];
a[i] = x + y, a[H + i] = x - y;
}
}
if constexpr (type == trans_type::superset_zeta) {
for (int i = 0; i < H; ++i) a[i] += a[H + i];
}
if constexpr (type == trans_type::superset_mobius) {
for (int i = 0; i < H; ++i) a[i] -= a[H + i];
}
if constexpr (type == trans_type::subset_zeta) {
for (int i = 0; i < H; ++i) a[H + i] += a[i];
}
if constexpr (type == trans_type::subset_mobius) {
for (int i = 0; i < H; ++i) a[H + i] -= a[i];
}
if constexpr (type == trans_type::ranked_zeta) {
for (int i = 0; i < H; ++i) ranked_add(a[H + i], a[i]);
}
if constexpr (type == trans_type::ranked_mobius) {
for (int i = 0; i < H; ++i) ranked_sub(a[H + i], a[i]);
}
}
}
template <trans_type type, int N, typename T>
inline void bitwise_transform_dispatch(vc<T>& a) {
if (len(a) == N) {
return bitwise_transform_fixed<type, N>(a.data());
}
if constexpr (N > 1) {
return bitwise_transform_dispatch<type, N / 2>(a);
}
}
template <trans_type type, typename T>
inline void bitwise_transform(vc<T>& a) {
int n = len(a);
assert(n >= 1);
assert((n & (n - 1)) == 0);
assert(n <= (1 << 25));
bitwise_transform_dispatch<type, 1 << 25>(a);
}
} // namespace bitwise
#line 4 "setfunc/ranked_zeta.hpp"
template <typename T, int LIM>
vc<array<T, LIM + 1>> ranked_zeta(const vc<T>& f) {
int n = topbit(len(f));
assert(n <= LIM);
assert(len(f) == 1 << n);
vc<array<T, LIM + 1>> Rf(1 << n);
for (int s = 0; s < (1 << n); ++s) Rf[s][popcnt(s)] = f[s];
bitwise::bitwise_transform<bitwise::trans_type::ranked_zeta>(Rf);
return Rf;
}
template <typename T, int LIM>
vc<T> ranked_mobius(vc<array<T, LIM + 1>>& Rf) {
bitwise::bitwise_transform<bitwise::trans_type::ranked_mobius>(Rf);
vc<T> f(len(Rf));
for (int s = 0; s < len(f); ++s) f[s] = Rf[s][popcnt(s)];
return f;
}
#line 4 "setfunc/subset_convolution.hpp"
template <typename T, int LIM = 20>
vc<T> subset_convolution_square(const vc<T>& A) {
auto RA = ranked_zeta<T, LIM>(A);
int n = topbit(len(RA));
FOR(s, len(RA)) {
auto& f = RA[s];
FOR_R(d, n + 1) {
T x = 0;
FOR(i, d + 1) x += f[i] * f[d - i];
f[d] = x;
}
}
return ranked_mobius<T, LIM>(RA);
}
template <typename T, int LIM = 20>
vc<T> subset_convolution(const vc<T>& A, const vc<T>& B) {
if (A == B) return subset_convolution_square(A);
auto RA = ranked_zeta<T, LIM>(A);
auto RB = ranked_zeta<T, LIM>(B);
int n = topbit(len(RA));
FOR(s, len(RA)) {
auto &f = RA[s], &g = RB[s];
FOR_R(d, n + 1) {
T x = 0;
FOR(i, d + 1) x += f[i] * g[d - i];
f[d] = x;
}
}
return ranked_mobius<T, LIM>(RA);
}
#line 4 "setfunc/sps_exp.hpp"
// sum_i 1/i! s^i, s^i is subset-convolution
template <typename mint, int LIM>
vc<mint> sps_exp(vc<mint>& s) {
const int N = topbit(len(s));
assert(len(s) == (1 << N) && s[0] == mint(0));
vc<mint> dp(1 << N);
dp[0] = mint(1);
FOR(i, N) {
vc<mint> a = {s.begin() + (1 << i), s.begin() + (2 << i)};
vc<mint> b = {dp.begin(), dp.begin() + (1 << i)};
a = subset_convolution<mint, LIM>(a, b);
copy(all(a), dp.begin() + (1 << i));
}
return dp;
}