多项式模板
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define clr(f, n) memset(f, 0, sizeof(int) * (n))
#define cpy(f, g, n) memcpy(f, g, sizeof(int) * (n))
using namespace std;
const int _G = 3, MOD = 998244353, N = 1 << 20 | 500;
int n, m, tr[N << 1], tf;
long long quickPower (long long x, long long y) {
long long res = 1;
while (y) {
if (y & 1) res = res * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return res;
}
const int invG = quickPower(_G, MOD - 2);
inline void tpre (int n) {
if (tf == n) return;
tf = n;
for (int i = 0; i < n; i ++) tr[i] = tr[i] = (tr[i >> 1] >> 1) | ((i & 1) ? n >> 1 : 0);
}
unsigned long long F[N << 1], W[N << 1] = {1};
inline void ntt (int *g, bool op, int n) {
tpre(n);
for (int i = 0; i < n; i ++) F[i] = (((long long) MOD << 5) + g[tr[i]]) % MOD;
for (int l = 1; l < n; l <<= 1) {
unsigned long long tG = quickPower(op ? _G : invG, (MOD - 1) / (l + l));
for (int i = 1; i < l; i ++) W[i] = W[i - 1] * tG % MOD;
for (int k = 0; k < n; k += l + l)
for (int p = 0; p < l; p ++) {
unsigned long long tt = W[p] * F[k | l | p] % MOD;
F[k | l | p] = F[k | p] + MOD - tt;
F[k | p] += tt;
}
if (l == (1 << 10))
for (int i = 0; i < n; i ++) F[i] %= MOD;
}
if (!op) {
unsigned long long invn = quickPower(n, MOD - 2);
for (int i = 0; i < n; i ++)
g[i] = F[i] % MOD * invn % MOD;
} else for (int i = 0; i < n; i ++) g[i] = F[i] % MOD;
}
inline void px (int *f, int *g, int n) {
for (int i = 0; i < n; i ++)
f[i] = 1ll * f[i] * g[i] % MOD;
}
#define Poly vector<int>
Poly operator + (const Poly &A, const Poly &B) {
Poly C = A;
C.resize(max(A.size(), B.size()));
for (int i = 0; i < B.size(); i ++) C[i] = (C[i] + B[i]) % MOD;
return C;
}
Poly operator - (const Poly &A, const Poly &B) {
Poly C = A;
C.resize(max(A.size(), B.size()));
for (int i = 0; i < B.size(); i ++) C[i] = (C[i] + MOD - B[i]) % MOD;
return C;
}
Poly operator * (const int c, const Poly &A) {
Poly C;
C.resize(A.size());
for (int i = 0; i < A.size(); i ++) C[i] = 1ll * c * A[i] % MOD;
return C;
}
int lim;
Poly operator * (const Poly &A, const Poly &B) {
static int a[N << 1], b[N << 1];
cpy(a, &A[0], A.size());
cpy(b, &B[0], B.size());
Poly C;
C.resize(min(lim, (int)(A.size() + B.size() - 1)));
int n = 1;
for (n; n < A.size() + B.size() - 1; n <<= 1);
ntt(a, 1, n);
ntt(b, 1, n);
px(a, b, n);
ntt(a, 0, n);
cpy(&C[0], a, C.size());
clr(a, n);
clr(b, n);
return C;
}
inline void pinv (const Poly &A, Poly &B, int n) {
if (n == 1) B.push_back(quickPower(A[0], MOD - 2));
else if (n & 1) {
pinv(A, B, -- n);
int sav = 0;
for (int i = 0; i < n; i ++) sav = (sav + 1ll * B[i] * A[n - i]) % MOD;
B.push_back(1ll * sav * quickPower(MOD - A[0], MOD - 2) % MOD);
} else {
pinv(A, B, n / 2);
Poly sA;
sA.resize(n);
cpy(&sA[0], &A[0], n);
B = 2 * B - B * B * sA;
B.resize(n);
}
}
//多项式乘法逆元
Poly pinv (const Poly &A) {
Poly C;
pinv(A, C, A.size());
return C;
}
int inv[N];
inline void Init () {
inv[1] = 1;
for (int i = 2; i <= lim; i ++)
inv[i] = 1ll * inv[MOD % i] * (MOD - MOD / i) % MOD;
}
//多项式求导
Poly dao (const Poly &A) {
Poly C = A;
for (int i = 1; i < C.size(); i ++)
C[i - 1] = 1ll * C[i] * i % MOD;
C.pop_back();
return C;
}
//多项式积分
Poly ints (const Poly &A) {
Poly C = A;
for (int i = C.size() - 1; i; i --)
C[i] = 1ll * C[i - 1] * inv[i] % MOD;
C[0] = 0;
return C;
}
//多项式ln
Poly ln (const Poly &A) {
return ints(dao(A) * pinv(A));
}
inline void pexp (const Poly &A, Poly &B, int n) {
if (n == 1) B.push_back(1);
else if (n & 1) {
pexp(A, B, n - 1);
n -= 2;
int sav = 0;
for (int i = 0; i <= n; i ++) sav = (sav + 1ll * (i + 1) * A[i + 1] % MOD * B[n - i]) % MOD;
B.push_back(1ll * sav * inv[n + 1] % MOD);
} else {
pexp(A, B, n / 2);
Poly lnB = B;
lnB.resize(n);
lnB = ln(lnB);
for (int i = 0; i < lnB.size(); i ++)
lnB[i] = (MOD + A[i] - lnB[i]) % MOD;
lnB[0] ++;
B = B * lnB;
B.resize(n);
}
}
//多项式exp
Poly pexp (const Poly &A) {
Poly C;
pexp(A, C, A.size());
return C;
}
Poly f, g;
int main () {
scanf("%d%d", &n, &m);
f.resize(n + 1);
g.resize(m + 1);
lim = n + m + 1;
for (int i = 0; i <= n; i ++) scanf("%d", &f[i]);
for (int i = 0; i <= m; i ++) scanf("%d", &g[i]);
f = f * g;
for (int i = 0; i < f.size(); i ++) printf("%d ", f[i]);
return 0;
}
模数表
//(g 是mod(r*2^k+1)的原根)
素数 r k g
3 1 1 2
5 1 2 2
17 1 4 3
97 3 5 5
193 3 6 5
257 1 8 3
7681 15 9 17
12289 3 12 11
40961 5 13 3
65537 1 16 3
786433 3 18 10
5767169 11 19 3
7340033 7 20 3
23068673 11 21 3
104857601 25 22 3
167772161 5 25 3
469762049 7 26 3
1004535809 479 21 3
2013265921 15 27 31
2281701377 17 27 3
3221225473 3 30 5
75161927681 35 31 3
77309411329 9 33 7
206158430209 3 36 22
2061584302081 15 37 7
2748779069441 5 39 3
6597069766657 3 41 5
39582418599937 9 42 5
79164837199873 9 43 5
263882790666241 15 44 7
1231453023109121 35 45 3
1337006139375617 19 46 3
3799912185593857 27 47 5
4222124650659841 15 48 19
7881299347898369 7 50 6
31525197391593473 7 52 3
180143985094819841 5 55 6
1945555039024054273 27 56 5
4179340454199820289 29 57 3
//大模数版
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define clr(f, n) memset(f, 0, sizeof(long long) * (n))
#define cpy(f, g, n) memcpy(f, g, sizeof(long long) * (n))
using namespace std;
const long long _G = 6, MOD = 180143985094819841ll, N = 1 << 20 | 500;
int n, m;
long long tr[N << 1], tf;
long long quickPower (long long x, long long y) {
long long res = 1;
while (y) {
if (y & 1) res = (__int128_t) res * x % MOD;
x = (__int128_t) x * x % MOD;
y >>= 1;
}
return res;
}
const long long invG = quickPower(_G, MOD - 2);
inline void tpre (int n) {
if (tf == n) return;
tf = n;
for (int i = 0; i < n; i ++) tr[i] = tr[i] = (tr[i >> 1] >> 1) | ((i & 1) ? n >> 1 : 0);
}
unsigned long long F[N << 1], W[N << 1] = {1};
inline void ntt (long long *g, bool op, int n) {
tpre(n);
for (int i = 0; i < n; i ++) F[i] = (((__int128_t) MOD << 5) + g[tr[i]]) % MOD;
for (int l = 1; l < n; l <<= 1) {
unsigned long long tG = quickPower(op ? _G : invG, (MOD - 1) / (l + l));
for (int i = 1; i < l; i ++) W[i] = (__int128_t) W[i - 1] * tG % MOD;
for (int k = 0; k < n; k += l + l)
for (int p = 0; p < l; p ++) {
unsigned long long tt = (__int128_t) W[p] * F[k | l | p] % MOD;
F[k | l | p] = F[k | p] + MOD - tt;
F[k | p] += tt;
}
if (l == (1 << 10))
for (int i = 0; i < n; i ++) F[i] %= MOD;
}
if (!op) {
unsigned long long invn = quickPower(n, MOD - 2);
for (int i = 0; i < n; i ++)
g[i] = (__int128_t) F[i] % MOD * invn % MOD;
} else for (int i = 0; i < n; i ++) g[i] = F[i] % MOD;
}
inline void px (long long *f, long long *g, int n) {
for (int i = 0; i < n; i ++)
f[i] = (__int128_t) f[i] * g[i] % MOD;
}
#define Poly vector<long long>
Poly operator + (const Poly &A, const Poly &B) {
Poly C = A;
C.resize(max(A.size(), B.size()));
for (int i = 0; i < B.size(); i ++) C[i] = ((__int128_t) C[i] + B[i]) % MOD;
return C;
}
Poly operator - (const Poly &A, const Poly &B) {
Poly C = A;
C.resize(max(A.size(), B.size()));
for (int i = 0; i < B.size(); i ++) C[i] = ((__int128_t) C[i] + MOD - B[i]) % MOD;
return C;
}
Poly operator * (const int c, const Poly &A) {
Poly C;
C.resize(A.size());
for (int i = 0; i < A.size(); i ++) C[i] = (__int128_t) c * A[i] % MOD;
return C;
}
int lim;
Poly operator * (const Poly &A, const Poly &B) {
static long long a[N << 1], b[N << 1];
cpy(a, &A[0], A.size());
cpy(b, &B[0], B.size());
Poly C;
C.resize(min(lim, (int)(A.size() + B.size() - 1)));
int n = 1;
for (n; n < A.size() + B.size() - 1; n <<= 1);
ntt(a, 1, n);
ntt(b, 1, n);
px(a, b, n);
ntt(a, 0, n);
cpy(&C[0], a, C.size());
clr(a, n);
clr(b, n);
return C;
}
Poly f, g;
int main () {
scanf("%d%d", &n, &m);
f.resize(n + 1);
g.resize(m + 1);
lim = n + m + 1;
for (int i = 0; i <= n; i ++) scanf("%lld", &f[i]);
for (int i = 0; i <= m; i ++) scanf("%lld", &g[i]);
f = f * g;
for (int i = 0; i < f.size(); i ++) printf("%lld ", f[i]);
return 0;
}
ntt分治
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define clr(f, n) memset(f, 0, sizeof(int) * (n))
#define cpy(f, g, n) memcpy(f, g, sizeof(int) * (n))
using namespace std;
const int _G = 3, MOD = 998244353, N = 1 << 20 | 500;
int tr[N << 1], tf;
long long quickPower (long long x, long long y) {
long long res = 1;
while (y) {
if (y & 1) res = res * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return res;
}
const int invG = quickPower(_G, MOD - 2);
inline void tpre (int n) {
if (tf == n) return;
tf = n;
for (int i = 0; i < n; i ++) tr[i] = tr[i] = (tr[i >> 1] >> 1) | ((i & 1) ? n >> 1 : 0);
}
unsigned long long F[N << 1], W[N << 1] = {1};
inline void ntt (int *g, bool op, int n) {
tpre(n);
for (int i = 0; i < n; i ++) F[i] = (((long long) MOD << 5) + g[tr[i]]) % MOD;
for (int l = 1; l < n; l <<= 1) {
unsigned long long tG = quickPower(op ? _G : invG, (MOD - 1) / (l + l));
for (int i = 1; i < l; i ++) W[i] = W[i - 1] * tG % MOD;
for (int k = 0; k < n; k += l + l)
for (int p = 0; p < l; p ++) {
unsigned long long tt = W[p] * F[k | l | p] % MOD;
F[k | l | p] = F[k | p] + MOD - tt;
F[k | p] += tt;
}
if (l == (1 << 10))
for (int i = 0; i < n; i ++) F[i] %= MOD;
}
if (!op) {
unsigned long long invn = quickPower(n, MOD - 2);
for (int i = 0; i < n; i ++)
g[i] = F[i] % MOD * invn % MOD;
} else for (int i = 0; i < n; i ++) g[i] = F[i] % MOD;
}
inline void px (int *f, int *g, int n) {
for (int i = 0; i < n; i ++)
f[i] = 1ll * f[i] * g[i] % MOD;
}
#define Poly vector<int>
Poly operator + (const Poly &A, const Poly &B) {
Poly C = A;
C.resize(max(A.size(), B.size()));
for (int i = 0; i < B.size(); i ++) C[i] = (C[i] + B[i]) % MOD;
return C;
}
Poly operator - (const Poly &A, const Poly &B) {
Poly C = A;
C.resize(max(A.size(), B.size()));
for (int i = 0; i < B.size(); i ++) C[i] = (C[i] + MOD - B[i]) % MOD;
return C;
}
Poly operator * (const int c, const Poly &A) {
Poly C;
C.resize(A.size());
for (int i = 0; i < A.size(); i ++) C[i] = 1ll * c * A[i] % MOD;
return C;
}
int lim;
Poly operator * (const Poly &A, const Poly &B) {
static int a[N << 1], b[N << 1];
cpy(a, &A[0], A.size());
cpy(b, &B[0], B.size());
Poly C;
C.resize(min(lim, (int)(A.size() + B.size() - 1)));
int n = 1;
for (n; n < A.size() + B.size() - 1; n <<= 1);
ntt(a, 1, n);
ntt(b, 1, n);
px(a, b, n);
ntt(a, 0, n);
cpy(&C[0], a, C.size());
clr(a, n);
clr(b, n);
return C;
}
int n;
Poly Ff, Gg;
void cdqntt (int l, int r) {
if (l == r) return;
int mid = (l + r) >> 1;
cdqntt(l, mid);
Poly f, g;
for (int i = l; i <= mid; i ++) f.push_back(Ff[i]);
for (int i = l, j = 0; i <= r; i ++, j ++) g.push_back(Gg[j]);
lim = r - l + 1;
f = f * g;
for (int i = ((r - l) >> 1) + 1; i <= r - l; i ++) Ff[l + i] = (Ff[l + i] + f[i]) % MOD;
cdqntt(mid + 1, r);
}
int main () {
scanf("%d", &n);
Ff.resize(n);
Gg.resize(n);
Ff[0] = 1;
Gg[0] = 0;
for (int i = 1; i < n; i ++) scanf("%d", &Gg[i]);
cdqntt(0, n - 1);
for (int i = 0; i < n; i ++) printf("%d ", Ff[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】