hly1204's library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub hly1204/library

:heavy_check_mark: test/set_power_series/inv_of_set_power_series.0.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/exp_of_set_power_series"

#include "modint.hpp"
#include "sps_basic.hpp"
#include <cassert>
#include <iostream>
#include <vector>

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    using mint = ModInt<998244353>;
    int n;
    std::cin >> n;
    std::vector<mint> a(1 << n);
    for (int i = 0; i < (1 << n); ++i) std::cin >> a[i];
    const auto expa = sps_exp(a);
    assert(sps_inv(sps_inv(expa)) == expa);
    for (int i = 0; i < (1 << n); ++i) std::cout << expa[i] << ' ';
    return 0;
}
#line 1 "test/set_power_series/inv_of_set_power_series.0.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/exp_of_set_power_series"

#line 2 "modint.hpp"

#include <iostream>
#include <type_traits>

// clang-format off
template<unsigned Mod> class ModInt {
    static_assert((Mod >> 31) == 0, "`Mod` must less than 2^(31)");
    template<typename Int>
    static std::enable_if_t<std::is_integral_v<Int>, unsigned> safe_mod(Int v) { using D = std::common_type_t<Int, unsigned>; return (v %= (int)Mod) < 0 ? (D)(v + (int)Mod) : (D)v; }
    struct PrivateConstructor {} static inline private_constructor{};
    ModInt(PrivateConstructor, unsigned v) : v_(v) {}
    unsigned v_;

public:
    static unsigned mod() { return Mod; }
    static ModInt from_raw(unsigned v) { return ModInt(private_constructor, v); }
    static ModInt zero() { return from_raw(0); }
    static ModInt one() { return from_raw(1); }
    bool is_zero() const { return v_ == 0; }
    bool is_one() const { return v_ == 1; }
    ModInt() : v_() {}
    template<typename Int, typename std::enable_if_t<std::is_signed_v<Int>, int> = 0> ModInt(Int v) : v_(safe_mod(v)) {}
    template<typename Int, typename std::enable_if_t<std::is_unsigned_v<Int>, int> = 0> ModInt(Int v) : v_(v % Mod) {}
    unsigned val() const { return v_; }
    ModInt operator-() const { return from_raw(v_ == 0 ? v_ : Mod - v_); }
    ModInt pow(long long e) const { if (e < 0) return inv().pow(-e); for (ModInt x(*this), res(from_raw(1));; x *= x) { if (e & 1) res *= x; if ((e >>= 1) == 0) return res; }}
    ModInt inv() const { int x1 = 1, x3 = 0, a = val(), b = Mod; while (b) { const int q = a / b, x1_old = x1, a_old = a; x1 = x3, x3 = x1_old - x3 * q, a = b, b = a_old - b * q; } return from_raw(x1 < 0 ? x1 + (int)Mod : x1); }
    template<bool Odd = (Mod & 1)> std::enable_if_t<Odd, ModInt> div_by_2() const { if (v_ & 1) return from_raw((v_ + Mod) >> 1); return from_raw(v_ >> 1); }
    ModInt &operator+=(const ModInt &a) { if ((v_ += a.v_) >= Mod) v_ -= Mod; return *this; }
    ModInt &operator-=(const ModInt &a) { if ((v_ += Mod - a.v_) >= Mod) v_ -= Mod; return *this; }
    ModInt &operator*=(const ModInt &a) { v_ = (unsigned long long)v_ * a.v_ % Mod; return *this; }
    ModInt &operator/=(const ModInt &a) { return *this *= a.inv(); }
    ModInt &operator++() { return *this += one(); }
    ModInt operator++(int) { ModInt o(*this); *this += one(); return o; }
    ModInt &operator--() { return *this -= one(); }
    ModInt operator--(int) { ModInt o(*this); *this -= one(); return o; }
    friend ModInt operator+(const ModInt &a, const ModInt &b) { return ModInt(a) += b; }
    friend ModInt operator-(const ModInt &a, const ModInt &b) { return ModInt(a) -= b; }
    friend ModInt operator*(const ModInt &a, const ModInt &b) { return ModInt(a) *= b; }
    friend ModInt operator/(const ModInt &a, const ModInt &b) { return ModInt(a) /= b; }
    friend bool operator==(const ModInt &a, const ModInt &b) { return a.v_ == b.v_; }
    friend bool operator!=(const ModInt &a, const ModInt &b) { return a.v_ != b.v_; }
    friend std::istream &operator>>(std::istream &a, ModInt &b) { int v; a >> v; b.v_ = safe_mod(v); return a; }
    friend std::ostream &operator<<(std::ostream &a, const ModInt &b) { return a << b.val(); }
};
// clang-format on
#line 2 "sps_basic.hpp"

#line 2 "subset_conv.hpp"

#include <cassert>
#include <vector>

template<typename Tp> inline std::vector<std::vector<Tp>> to_ranked(const std::vector<Tp> &A) {
    const int N = A.size();
    int LogN    = 0;
    while ((1 << LogN) != N) ++LogN;
    std::vector res(LogN + 1, std::vector<Tp>(N));
    for (int i = 0; i < N; ++i) res[__builtin_popcount(i)][i] = A[i];
    return res;
}

template<typename Tp> inline std::vector<Tp> from_ranked(const std::vector<std::vector<Tp>> &A) {
    const int N = A[0].size();
    std::vector<Tp> res(N);
    for (int i = 0; i < N; ++i) res[i] = A[__builtin_popcount(i)][i];
    return res;
}

template<typename Iterator> inline void subset_zeta_n(Iterator a, int n) {
    assert((n & (n - 1)) == 0);
    for (int i = 2; i <= n; i *= 2)
        for (int j = 0; j < n; j += i)
            for (int k = j; k < j + i / 2; ++k) a[k + i / 2] += a[k];
}

template<typename Tp> inline void subset_zeta(std::vector<Tp> &a) {
    subset_zeta_n(a.begin(), a.size());
}

template<typename Iterator> inline void subset_moebius_n(Iterator a, int n) {
    assert((n & (n - 1)) == 0);
    for (int i = 2; i <= n; i *= 2)
        for (int j = 0; j < n; j += i)
            for (int k = j; k < j + i / 2; ++k) a[k + i / 2] -= a[k];
}

template<typename Tp> inline void subset_moebius(std::vector<Tp> &a) {
    subset_moebius_n(a.begin(), a.size());
}

template<typename Tp>
inline std::vector<Tp> subset_convolution(const std::vector<Tp> &A, const std::vector<Tp> &B) {
    assert(A.size() == B.size());
    const int N = A.size();
    int LogN    = 0;
    while ((1 << LogN) != N) ++LogN;
    auto rankedA = to_ranked(A);
    auto rankedB = to_ranked(B);

    for (int i = 0; i <= LogN; ++i) {
        subset_zeta(rankedA[i]);
        subset_zeta(rankedB[i]);
    }

    // see: https://codeforces.com/blog/entry/126418
    // see: https://oeis.org/A025480
    std::vector<int> map(LogN + 1);
    for (int i = 0; i <= LogN; ++i) map[i] = (i & 1) ? map[i / 2] : i / 2;

    std::vector rankedAB(LogN / 2 + 1, std::vector<Tp>(N));
    for (int i = 0; i <= LogN; ++i)
        for (int j = 0; i + j <= LogN; ++j)
            for (int k = (1 << j) - 1; k < N; ++k)
                rankedAB[map[i + j]][k] += rankedA[i][k] * rankedB[j][k];

    for (int i = 0; i <= LogN / 2; ++i) subset_moebius(rankedAB[i]);

    std::vector<Tp> res(N);
    for (int i = 0; i < N; ++i) res[i] = rankedAB[map[__builtin_popcount(i)]][i];
    return res;
}
#line 6 "sps_basic.hpp"

namespace detail {

template<typename Tp> void sps_hadamard_inplace(std::vector<std::vector<Tp>> &rankedA,
                                                const std::vector<std::vector<Tp>> &rankedB,
                                                int LogN) {
    const int N = (1 << LogN);
    for (int i = LogN; i >= 0; --i) {
        for (int j = 0; j < N; ++j) rankedA[i][j] *= rankedB[0][j];
        for (int j = 1; j <= i; ++j)
            for (int k = (1 << j) - 1; k < N; ++k)
                rankedA[i][k] += rankedA[i - j][k] * rankedB[j][k];
    }
}

} // namespace detail

template<typename Tp> inline std::vector<Tp> sps_inv(const std::vector<Tp> &A) {
    const int N = A.size();
    assert(N > 0);
    assert((N & (N - 1)) == 0);
    assert(A[0] != 0);
    int LogN = 0;
    while ((1 << LogN) != N) ++LogN;
    std::vector<Tp> res(N);
    res[0] = A[0].inv();
    std::vector rankedInvA(LogN, std::vector<Tp>(N / 2));
    for (int i = 0; i < LogN; ++i) {
        std::vector rankedA(i + 1, std::vector<Tp>(1 << i));
        for (int j = 0; j < (1 << i); ++j) rankedA[__builtin_popcount(j)][j] = A[j + (1 << i)];
        for (int j = 0; j <= i; ++j) subset_zeta(rankedA[j]);

        for (int j = (1 << i) / 2; j < (1 << i); ++j) rankedInvA[__builtin_popcount(j)][j] = res[j];
        for (int j = 0; j <= i; ++j) {
            subset_zeta_n(rankedInvA[j].begin() + (1 << i) / 2, (1 << i) / 2);
            for (int k = 0; k < (1 << i) / 2; ++k)
                rankedInvA[j][k + (1 << i) / 2] += rankedInvA[j][k];
        }

        detail::sps_hadamard_inplace(rankedA, rankedInvA, i);
        detail::sps_hadamard_inplace(rankedA, rankedInvA, i);

        for (int j = 0; j <= i; ++j) subset_moebius(rankedA[j]);
        for (int j = 0; j < (1 << i); ++j) res[j + (1 << i)] = -rankedA[__builtin_popcount(j)][j];
    }
    return res;
}

template<typename Tp> inline std::vector<Tp> sps_log(const std::vector<Tp> &A) {
    const int N = A.size();
    assert(N > 0);
    assert((N & (N - 1)) == 0);
    assert(A[0] == 1);
    int LogN = 0;
    while ((1 << LogN) != N) ++LogN;
    std::vector<Tp> res(N);
    std::vector<Tp> invA = {Tp(1)};
    invA.resize(N / 2);
    std::vector rankedInvA(LogN, std::vector<Tp>(N / 2));
    for (int i = 0; i < LogN; ++i) {
        std::vector rankedA(i + 1, std::vector<Tp>(1 << i));
        for (int j = 0; j < (1 << i); ++j) rankedA[__builtin_popcount(j)][j] = A[j + (1 << i)];
        for (int j = 0; j <= i; ++j) subset_zeta(rankedA[j]);

        for (int j = (1 << i) / 2; j < (1 << i); ++j)
            rankedInvA[__builtin_popcount(j)][j] = invA[j];
        for (int j = 0; j <= i; ++j) {
            subset_zeta_n(rankedInvA[j].begin() + (1 << i) / 2, (1 << i) / 2);
            for (int k = 0; k < (1 << i) / 2; ++k)
                rankedInvA[j][k + (1 << i) / 2] += rankedInvA[j][k];
        }

        detail::sps_hadamard_inplace(rankedA, rankedInvA, i);
        auto rankedLogA = rankedA;
        for (int j = 0; j <= i; ++j) subset_moebius(rankedLogA[j]);
        for (int j = 0; j < (1 << i); ++j) res[j + (1 << i)] = rankedLogA[__builtin_popcount(j)][j];
        if (i == LogN - 1) break;
        detail::sps_hadamard_inplace(rankedA, rankedInvA, i);

        for (int j = 0; j <= i; ++j) subset_moebius(rankedA[j]);
        for (int j = 0; j < (1 << i); ++j) invA[j + (1 << i)] = -rankedA[__builtin_popcount(j)][j];
    }
    return res;
}

// returns exp(0 + tx_1 + ...) in R[x_1,...,x_n]/(x_1^2,...,x_n^2)
template<typename Tp> inline std::vector<Tp> sps_exp(const std::vector<Tp> &A) {
    const int N = A.size();
    assert(N > 0);
    assert((N & (N - 1)) == 0);
    assert(A[0] == 0);
    int LogN = 0;
    while ((1 << LogN) != N) ++LogN;
    std::vector<Tp> res(N);
    res[0] = 1;
    std::vector rankedExpA(LogN, std::vector<Tp>(N / 2));
    for (int i = 0; i < LogN; ++i) {
        std::vector rankedA(i + 1, std::vector<Tp>(1 << i));
        for (int j = 0; j < (1 << i); ++j) rankedA[__builtin_popcount(j)][j] = A[j + (1 << i)];
        for (int j = 0; j <= i; ++j) subset_zeta(rankedA[j]);

        for (int j = (1 << i) / 2; j < (1 << i); ++j) rankedExpA[__builtin_popcount(j)][j] = res[j];
        for (int j = 0; j <= i; ++j) {
            subset_zeta_n(rankedExpA[j].begin() + (1 << i) / 2, (1 << i) / 2);
            for (int k = 0; k < (1 << i) / 2; ++k)
                rankedExpA[j][k + (1 << i) / 2] += rankedExpA[j][k];
        }

        std::vector<int> map(i + 1);
        for (int j = 0; j <= i; ++j) map[j] = (j & 1) ? map[j / 2] : j / 2;

        std::vector ExpAA(i / 2 + 1, std::vector<Tp>(1 << i));
        for (int j = 0; j <= i; ++j)
            for (int k = 0; j + k <= i; ++k)
                for (int l = (1 << k) - 1; l < (1 << i); ++l)
                    ExpAA[map[j + k]][l] += rankedExpA[j][l] * rankedA[k][l];
        for (int j = 0; j <= i / 2; ++j) subset_moebius(ExpAA[j]);

        for (int j = 0; j < (1 << i); ++j) res[j + (1 << i)] = ExpAA[map[__builtin_popcount(j)]][j];
    }
    return res;
}
#line 8 "test/set_power_series/inv_of_set_power_series.0.test.cpp"

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    using mint = ModInt<998244353>;
    int n;
    std::cin >> n;
    std::vector<mint> a(1 << n);
    for (int i = 0; i < (1 << n); ++i) std::cin >> a[i];
    const auto expa = sps_exp(a);
    assert(sps_inv(sps_inv(expa)) == expa);
    for (int i = 0; i < (1 << n); ++i) std::cout << expa[i] << ' ';
    return 0;
}
Back to top page