模板 - 数学 - 快速傅里叶变换/快速数论变换(FFT/NTT)
先看看。
通常模数常见的有998244353,1004535809,469762049,这几个的原根都是3。
所求的项数还不能超过2的23次方(因为998244353的分解)。
感觉没啥用。
#include <cstdio> #include <cstring> template <class T> inline void swap(T &a, T &b) { T c; c = a; a = b; b = c; } const int siz = 500005; const int P = 998244353, G = 3; inline int pow(int a, int b) { int r = 1; while (b) { if (b & 1) r = 1LL * r * a % P; b >>= 1, a = 1LL * a * a % P; } return r; } inline void calculateNTT(int *s, int n, int f) { { int cnt = 0; static int rev[siz]; while (n >> cnt)++cnt; --cnt; memset(rev, 0, sizeof rev); for (int i = 0; i < n; ++i) { rev[i] |= rev[i >> 1] >> 1; rev[i] |= (i & 1) << (cnt - 1); } for (int i = 0; i < n; ++i)if (i < rev[i])swap(s[i], s[rev[i]]); } { for (int i = 1; i < n; i <<= 1) { int wn = pow(G, (P - 1) / (i * 2)); if (f == -1)wn = pow(wn, P - 2); for (int j = 0; j < n; j += (i << 1)) { int wk = 1; for (int k = 0; k < i; ++k, wk = 1LL * wk * wn % P) { int x = s[j + k]; int y = 1LL * s[i + j + k] * wk % P; s[j + k] = x + y; s[i + j + k] = x - y; s[j + k] = (s[j + k] % P + P) % P; s[i + j + k] = (s[i + j + k] % P + P) % P; } } } } { if (f == -1) { int inv = pow(n, P - 2); for (int i = 0; i < n; ++i) s[i] = 1LL * s[i] * inv % P; } } } signed main(void) { static char sa[siz]; static char sb[siz]; scanf("%s", sa); scanf("%s", sb); static int la, a[siz]; static int lb, b[siz]; la = strlen(sa); lb = strlen(sb); for (int i = 0; i < la; ++i)a[i] = sa[la - i - 1] - '0'; for (int i = 0; i < lb; ++i)b[i] = sb[lb - i - 1] - '0'; int len; for (len = 1; len < la || len < lb; len <<= 1); calculateNTT(a, len << 1, +1); calculateNTT(b, len << 1, +1); for (int i = 0; i < len << 1; ++i)a[i] = 1LL * a[i] * b[i] % P; calculateNTT(a, len << 1, -1); for (int i = 0; i < len << 1; ++i)a[i + 1] += a[i] / 10, a[i] = a[i] % 10; len <<= 1; while (!a[len])--len; for (int i = len; ~i; --i)printf("%d", a[i]); puts(""); }
快速傅里叶变换FFT