传送门 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;
}