P4245 MTT

题意

传送门 P4245 【模板】任意模数多项式乘法

题解

对于 p = 1 0 9 p=10^9 p=109 范围的模数以及最高次在 n , m = 1 0 5 n,m=10^5 n,m=105 范围的多项式,结果多项式的每一项系数上界为 p 2 ⋅ ( n + m ) p^2\cdot (n + m) p2(n+m),使用三模数NTT 求解,最后根据中国剩余定理合并即可。考虑到数据范围,需要使用 __int128。总时间复杂度 O ( ( n + m ) log ⁡ ( n + m ) ) O\big((n+m)\log (n+m)\big) O((n+m)log(n+m))

#include 
using namespace std;
namespace MTT {
using ll = long long;
constexpr int N = 3;
constexpr ll MOD[N] = {998244353, 1004535809, 469762049}, G = 3;
ll power(ll x, ll n, ll mod) {
    ll res = 1;
    x %= mod;
    while (n > 0) {
        if (n & 1) {
            res = res * x % mod;
        }
        x = x * x % mod, n >>= 1;
    }
    return res;
}

vector<int> rev;
ll _mod;
struct Poly : vector<ll> {
    Poly() {}
    Poly(int n) : vector<ll>(n) {}
    Poly(const vector<ll> &a) : vector<ll>(a) {}
    Poly(const initializer_list<ll> &list) : vector<ll>(list) {}
    void fft(int n, bool inverse) {
        if ((int)rev.size() != n) {
            rev.resize(n);
            for (int i = 0; i < n; ++i)
                rev[i] = rev[i >> 1] >> 1 | (i & 1 ? n >> 1 : 0);
        }
        resize(n);
        for (int i = 0; i < n; ++i)
            if (i < rev[i])
                std::swap(at(i), at(rev[i]));
        ll mod = _mod;
        for (int m = 1; m < n; m <<= 1) {
            int m2 = m << 1;
            ll _w = power(inverse ? power(G, mod - 2, mod) : G, (mod - 1) / m2, mod);
            for (int i = 0; i < n; i += m2)
                for (int w = 1, j = 0; j < m; ++j, w = w * _w % mod) {
                    ll &x = at(i + j), &y = at(i + j + m), t = w * y % mod;
                    y = x - t;
                    if (y < 0)
                        y += mod;
                    x += t;
                    if (x >= mod)
                        x -= mod;
                }
        }
    }
    void dft(int n) { fft(n, 0); };
    void idft(int n) {
        fft(n, 1);
        ll mod = _mod;
        for (int i = 0, inv = power(n, mod - 2, mod); i < n; ++i)
            at(i) = at(i) * inv % mod;
    }
    Poly operator*(const Poly &p) const {
        auto a = *this, b = p;
        int k = 1, n = a.size() + b.size() - 1;
        while (k < n)
            k <<= 1;
        a.dft(k), b.dft(k);
        ll mod = _mod;
        for (int i = 0; i < k; ++i)
            a[i] = a[i] * b[i] % mod;
        a.idft(k);
        a.resize(n);
        return a;
    }
};

vector<ll> mul(vector<ll> &a, vector<ll> &b, ll p) {
    int n = a.size(), m = b.size();
    vector<Poly> tmp(N);
    for (int i = 0; i < N; ++i) {
        _mod = MOD[i];
        Poly f(a), g(b);
        tmp[i] = f * g;
    }
    using lll = __int128;
    vector<lll> c(n + m - 1);
    lll _p = 1;
    for (int i = 0; i < N; ++i) {
        _p *= MOD[i];
    }
    for (int i = 0; i < N; ++i) {
        ll x = 1;
        for (int j = 0; j < N; ++j) {
            if (i != j) {
                x *= MOD[j];
            }
        }
        ll y = power(x, MOD[i] - 2, MOD[i]);
        for (int j = 0; j < n + m - 1; ++j) {
            c[j] += (lll)tmp[i][j] * x * y;
        }
    }
    vector<ll> res(n + m - 1);
    for (int i = 0; i < n + m - 1; ++i) {
        res[i] = c[i] % _p % p;
    }
    return res;
}
}  // namespace MTT
using ll = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m, p;
    cin >> n >> m >> p;
    n += 1;
    m += 1;
    vector<ll> f(n);
    vector<ll> g(m);
    for (int i = 0; i < n; ++i) {
        cin >> f[i];
    }
    for (int i = 0; i < m; ++i) {
        cin >> g[i];
    }
    auto res = MTT::mul(f, g, p);
    for (int i = 0; i < n + m - 1; ++i) {
        cout << res[i] << " \n"[i + 1 == n + m - 1];
    }

    return 0;
}

你可能感兴趣的:(数学,算法)