Hedwig's Library

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

View on GitHub

:warning: math/fast_fourier_transform.cpp

Depends on

Code

#pragma once
#include <bits/stdc++.h>
using namespace std;
#include "../template/const.hpp"
#include "./mint.cpp"

class FastFourierTransform {
  private:
    inline static void fft(vector<complex<double>> &F) {
        int degree = F.size();
        if (degree == 1) return;
        vector<complex<double>> even, odd;
        for (int i = 0; i < degree / 2; i++) {
            even.push_back(F[i << 1]);
            odd.push_back(F[i << 1 | 1]);
        }
        fft(even);
        fft(odd);
        complex<double> x = 1, zeta = polar(1.0, 2 * PI / degree);
        for (int i = 0; i < degree; i++) {
            F[i] = even[i % (degree / 2)] + x * odd[i % (degree / 2)];
            x *= zeta;
        }
    }

    inline static void ifft(vector<complex<double>> &F) {
        int degree = F.size();
        if (degree == 1) return;
        vector<complex<double>> even, odd;
        for (int i = 0; i < degree / 2; i++) {
            even.push_back(F[i << 1]);
            odd.push_back(F[i << 1 | 1]);
        }
        ifft(even);
        ifft(odd);
        complex<double> x = 1, zeta = polar(1.0, -2 * PI / degree);
        for (int i = 0; i < degree; i++) {
            F[i] = even[i % (degree / 2)] + x * odd[i % (degree / 2)];
            x *= zeta;
        }
    }

  public:
    template <class T>
    inline static vector<double> multiply(vector<T> F, vector<T> G) {
        int degree = 1;
        while (degree < F.size() + G.size() - 1)
            degree *= 2;
        vector<complex<double>> nF(degree, 0), nG(degree, 0);
        for (int i = 0; i < F.size(); i++)
            nF[i] = F[i];
        for (int i = 0; i < G.size(); i++)
            nG[i] = G[i];
        fft(nF);
        fft(nG);
        for (int i = 0; i < degree; i++) {
            nF[i] *= nG[i];
        }
        ifft(nF);
        vector<double> ret(degree);
        for (int i = 0; i < degree; i++) {
            ret[i] = nF[i].real() / degree;
        }
        return ret;
    }
};

//非再帰できたはやい

class FastFourierTransform {
  private:
    inline static void fft(vector<complex<double>> &F, bool inverse, int bit_len) {
        int degree = F.size();
        for (int i = 0; i < degree; i++) {
            int j = 0;
            for (int k = 0; k < bit_len; k++)
                j |= (i >> k & 1) << (bit_len - k - 1);
            if (i < j) swap(F[i], F[j]);
        }
        for (int b = 1; b < degree; b <<= 1) {
            complex<double> x = 1, zeta = polar(1.0, PI / b * (inverse ? 1 : -1));
            for (int j = 0; j < b; j++) {
                for (int k = 0; k < degree; k += (b << 1)) {
                    complex<double> s = F[j + k], t = F[j + k + b] * x;
                    F[j + k]     = s + t;
                    F[j + k + b] = s - t;
                }
                x *= zeta;
            }
        }
        if (inverse) {
            for (int i = 0; i < degree; i++)
                F[i] /= degree;
        }
    }

  public:
    template <class T>
    inline static vector<long long> multiply(vector<T> &F, vector<T> &G) {
        int s      = F.size() + G.size() - 1;
        int degree = 1, bit_len = 0;
        while (degree < s)
            degree <<= 1, bit_len++;
        vector<complex<double>> nF(degree, 0), nG(degree, 0);
        for (int i = 0; i < F.size(); i++)
            nF[i] = F[i];
        for (int i = 0; i < G.size(); i++)
            nG[i] = G[i];
        fft(nF, false, bit_len);
        fft(nG, false, bit_len);
        for (int i = 0; i < degree; i++)
            nF[i] *= nG[i];
        fft(nF, true, bit_len);
        vector<long long> ret(s);
        for (int i = 0; i < s; i++)
            ret[i] = (long long)(nF[i].real() + 0.5);
        return ret;
    }
};

struct NumberTheoreticalTransform {
    const int premitive_root = 3; // primitive root of 998244353
    const int MOD            = 998244353;
    NumberTheoreticalTransform() {}
    inline void ntt(vector<mint> &F, bool inverse, int bit_len) {
        int degree = F.size();
        for (int i = 0; i < degree; i++) {
            int j = 0;
            for (int k = 0; k < bit_len; k++)
                j |= (i >> k & 1) << (bit_len - k - 1);
            if (i < j) swap(F[i], F[j]);
        }
        for (int b = 1; b < degree; b <<= 1) {
            mint x = 1, zeta = mint(premitive_root).pow((MOD - 1) / (b << 1));
            if (inverse) zeta = zeta.inverse();
            for (int j = 0; j < b; ++j) {
                for (int k = 0; k < degree; k += (b << 1)) {
                    mint s = F[j + k], t = F[j + k + b] * x;
                    F[j + k]     = s + t;
                    F[j + k + b] = s - t;
                }
                x *= zeta;
            }
        }
        if (inverse) {
            mint inv = mint(degree).inverse();
            for (int i = 0; i < degree; i++)
                F[i] *= inv;
        }
    }
    inline vector<mint> multiply(vector<mint> &F, vector<mint> &G) {
        int s      = F.size() + G.size() - 1;
        int degree = 1, bit_len = 0;
        while (degree < s)
            degree <<= 1, bit_len++;
        vector<mint> nF(degree, 0), nG(degree, 0);
        for (int i = 0; i < F.size(); i++)
            nF[i] = F[i];
        for (int i = 0; i < G.size(); i++)
            nG[i] = G[i];
        ntt(nF, false, bit_len);
        ntt(nG, false, bit_len);
        for (int i = 0; i < degree; i++)
            nF[i] *= nG[i];
        ntt(nF, true, bit_len);
        return nF;
    }
} ntt;
#line 2 "math/fast_fourier_transform.cpp"
#include <bits/stdc++.h>
using namespace std;
#line 2 "template/const.hpp"
constexpr int INF        = 1000'000'000;
constexpr long long HINF = 4000'000'000'000'000'000;
constexpr long long MOD  = 998244353;
constexpr double EPS     = 1e-6;
constexpr double PI      = 3.14159265358979;
#line 3 "math/mint.cpp"
using namespace std;

template <int MOD>
struct ModInt {
  public:
    long long x;
    ModInt(long long x = 0) : x((x % MOD + MOD) % MOD) {}
    constexpr ModInt &operator+=(const ModInt a) noexcept {
        if ((x += a.x) >= MOD) x -= MOD;
        return *this;
    }
    constexpr ModInt &operator-=(const ModInt a) noexcept {
        if ((x += MOD - a.x) >= MOD) x -= MOD;
        return *this;
    }
    constexpr ModInt &operator*=(const ModInt a) noexcept {
        (x *= a.x) %= MOD;
        return *this;
    }
    constexpr ModInt &operator/=(const ModInt a) noexcept { return *this *= a.inverse(); }

    constexpr ModInt operator+(const ModInt a) const noexcept { return ModInt(*this) += a.x; }
    constexpr ModInt operator-(const ModInt a) const noexcept { return ModInt(*this) -= a.x; }
    constexpr ModInt operator*(const ModInt a) const noexcept { return ModInt(*this) *= a.x; }
    constexpr ModInt operator/(const ModInt a) const noexcept { return ModInt(*this) /= a.x; }

    friend constexpr std::ostream &operator<<(std::ostream &os, const ModInt<MOD> a) noexcept { return os << a.x; }
    friend constexpr std::istream &operator>>(std::istream &is, ModInt<MOD> &a) noexcept {
        is >> a.x;
        a.x = (a.x % MOD + MOD) % MOD;
        return is;
    }

    ModInt inverse() const noexcept { // x ^ (-1)
        long long a = x, b = MOD, p = 1, q = 0;
        while (b) {
            long long d = a / b;
            a -= d * b;
            swap(a, b);
            p -= d * q;
            swap(p, q);
        }
        return ModInt(p);
    }
    ModInt pow(long long N) const noexcept { // x ^ N
        ModInt a = 1;
        ModInt y = this->x;
        while (N) {
            if (N & 1) a *= y;
            y *= y;
            N >>= 1;
        }
        return a;
    }
};

template <typename U, int MOD>
inline ModInt<MOD> operator*(const U &c, const ModInt<MOD> &a) { return {c * a.x}; }

using mint = ModInt<998244353>;
#line 6 "math/fast_fourier_transform.cpp"

class FastFourierTransform {
  private:
    inline static void fft(vector<complex<double>> &F) {
        int degree = F.size();
        if (degree == 1) return;
        vector<complex<double>> even, odd;
        for (int i = 0; i < degree / 2; i++) {
            even.push_back(F[i << 1]);
            odd.push_back(F[i << 1 | 1]);
        }
        fft(even);
        fft(odd);
        complex<double> x = 1, zeta = polar(1.0, 2 * PI / degree);
        for (int i = 0; i < degree; i++) {
            F[i] = even[i % (degree / 2)] + x * odd[i % (degree / 2)];
            x *= zeta;
        }
    }

    inline static void ifft(vector<complex<double>> &F) {
        int degree = F.size();
        if (degree == 1) return;
        vector<complex<double>> even, odd;
        for (int i = 0; i < degree / 2; i++) {
            even.push_back(F[i << 1]);
            odd.push_back(F[i << 1 | 1]);
        }
        ifft(even);
        ifft(odd);
        complex<double> x = 1, zeta = polar(1.0, -2 * PI / degree);
        for (int i = 0; i < degree; i++) {
            F[i] = even[i % (degree / 2)] + x * odd[i % (degree / 2)];
            x *= zeta;
        }
    }

  public:
    template <class T>
    inline static vector<double> multiply(vector<T> F, vector<T> G) {
        int degree = 1;
        while (degree < F.size() + G.size() - 1)
            degree *= 2;
        vector<complex<double>> nF(degree, 0), nG(degree, 0);
        for (int i = 0; i < F.size(); i++)
            nF[i] = F[i];
        for (int i = 0; i < G.size(); i++)
            nG[i] = G[i];
        fft(nF);
        fft(nG);
        for (int i = 0; i < degree; i++) {
            nF[i] *= nG[i];
        }
        ifft(nF);
        vector<double> ret(degree);
        for (int i = 0; i < degree; i++) {
            ret[i] = nF[i].real() / degree;
        }
        return ret;
    }
};

//非再帰できたはやい

class FastFourierTransform {
  private:
    inline static void fft(vector<complex<double>> &F, bool inverse, int bit_len) {
        int degree = F.size();
        for (int i = 0; i < degree; i++) {
            int j = 0;
            for (int k = 0; k < bit_len; k++)
                j |= (i >> k & 1) << (bit_len - k - 1);
            if (i < j) swap(F[i], F[j]);
        }
        for (int b = 1; b < degree; b <<= 1) {
            complex<double> x = 1, zeta = polar(1.0, PI / b * (inverse ? 1 : -1));
            for (int j = 0; j < b; j++) {
                for (int k = 0; k < degree; k += (b << 1)) {
                    complex<double> s = F[j + k], t = F[j + k + b] * x;
                    F[j + k]     = s + t;
                    F[j + k + b] = s - t;
                }
                x *= zeta;
            }
        }
        if (inverse) {
            for (int i = 0; i < degree; i++)
                F[i] /= degree;
        }
    }

  public:
    template <class T>
    inline static vector<long long> multiply(vector<T> &F, vector<T> &G) {
        int s      = F.size() + G.size() - 1;
        int degree = 1, bit_len = 0;
        while (degree < s)
            degree <<= 1, bit_len++;
        vector<complex<double>> nF(degree, 0), nG(degree, 0);
        for (int i = 0; i < F.size(); i++)
            nF[i] = F[i];
        for (int i = 0; i < G.size(); i++)
            nG[i] = G[i];
        fft(nF, false, bit_len);
        fft(nG, false, bit_len);
        for (int i = 0; i < degree; i++)
            nF[i] *= nG[i];
        fft(nF, true, bit_len);
        vector<long long> ret(s);
        for (int i = 0; i < s; i++)
            ret[i] = (long long)(nF[i].real() + 0.5);
        return ret;
    }
};

struct NumberTheoreticalTransform {
    const int premitive_root = 3; // primitive root of 998244353
    const int MOD            = 998244353;
    NumberTheoreticalTransform() {}
    inline void ntt(vector<mint> &F, bool inverse, int bit_len) {
        int degree = F.size();
        for (int i = 0; i < degree; i++) {
            int j = 0;
            for (int k = 0; k < bit_len; k++)
                j |= (i >> k & 1) << (bit_len - k - 1);
            if (i < j) swap(F[i], F[j]);
        }
        for (int b = 1; b < degree; b <<= 1) {
            mint x = 1, zeta = mint(premitive_root).pow((MOD - 1) / (b << 1));
            if (inverse) zeta = zeta.inverse();
            for (int j = 0; j < b; ++j) {
                for (int k = 0; k < degree; k += (b << 1)) {
                    mint s = F[j + k], t = F[j + k + b] * x;
                    F[j + k]     = s + t;
                    F[j + k + b] = s - t;
                }
                x *= zeta;
            }
        }
        if (inverse) {
            mint inv = mint(degree).inverse();
            for (int i = 0; i < degree; i++)
                F[i] *= inv;
        }
    }
    inline vector<mint> multiply(vector<mint> &F, vector<mint> &G) {
        int s      = F.size() + G.size() - 1;
        int degree = 1, bit_len = 0;
        while (degree < s)
            degree <<= 1, bit_len++;
        vector<mint> nF(degree, 0), nG(degree, 0);
        for (int i = 0; i < F.size(); i++)
            nF[i] = F[i];
        for (int i = 0; i < G.size(); i++)
            nG[i] = G[i];
        ntt(nF, false, bit_len);
        ntt(nG, false, bit_len);
        for (int i = 0; i < degree; i++)
            nF[i] *= nG[i];
        ntt(nF, true, bit_len);
        return nF;
    }
} ntt;
Back to top page