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))。

cpp 复制代码
#include <bits/stdc++.h>
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;
}
相关推荐
Jerry5 小时前
LeetCode 28. 找出字符串中第一个匹配项的下标
算法
Jerry7 小时前
LeetCode 459. 重复的子字符串
算法
海石10 小时前
1500分的题目,确实有实力,不过还是我略胜一筹
算法·leetcode
海石10 小时前
【记忆化搜索】条条大路通AC,走好适合你的那一条,走到后再考虑走得快
算法·leetcode
Jerry12 小时前
LeetCode 151. 反转字符串中的单词
算法
a11177614 小时前
LM 算法迭代过程动画演示(SLAM)
算法
头茬韭菜14 小时前
Context 的生死抉择:四层压缩、截断算法与 Session Memory
算法·ai
Jerry14 小时前
LeetCode 541. 反转字符串 II
算法
Jerry15 小时前
LeetCode 344. 反转字符串
算法
搞科研的小刘选手15 小时前
【香港大学主办&IEEE出版】第六届计算机视觉、应用与算法国际学术会议(CVAA 2026)
算法·计算机视觉·应用·学术会议