快速数论变换
简介¶
NTT 解决的是多项式乘法带模数的情况,可以说有些受模数的限制,数也比较大,
但是它比较方便呀毕竟没有复数部分
学习 NTT 之前……¶
生成子群¶
子群:群
拉格朗日定理:
生成子群:
阶:群
考虑群
阶就是满足
原根¶
模
离散对数:
因为
求原根可以证明满足
的最小的
恒成立,
NTT¶
对于质数
然后因为这里涉及到数论变化,所以这里的
常见的有
就是
迭代到长度
接下来放一个大数相乘的模板
参考网址如下https://blog.csdn.net/blackjack_/article/details/79346433
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | #include <algorithm> #include <bitset> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <set> #include <string> #include <vector> using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch <= '9' && ch >= '0') { x = 10 * x + ch - '0'; ch = getchar(); } return x * f; } void print(int x) { if (x < 0) putchar('-'), x = -x; if (x >= 10) print(x / 10); putchar(x % 10 + '0'); } const int N = 300100, P = 998244353; inline int qpow(int x, int y) { int res(1); while (y) { if (y & 1) res = 1ll * res * x % P; x = 1ll * x * x % P; y >>= 1; } return res; } int r[N]; void ntt(int *x, int lim, int opt) { register int i, j, k, m, gn, g, tmp; for (i = 0; i < lim; ++i) if (r[i] < i) swap(x[i], x[r[i]]); for (m = 2; m <= lim; m <<= 1) { k = m >> 1; gn = qpow(3, (P - 1) / m); for (i = 0; i < lim; i += m) { g = 1; for (j = 0; j < k; ++j, g = 1ll * g * gn % P) { tmp = 1ll * x[i + j + k] * g % P; x[i + j + k] = (x[i + j] - tmp + P) % P; x[i + j] = (x[i + j] + tmp) % P; } } } if (opt == -1) { reverse(x + 1, x + lim); register int inv = qpow(lim, P - 2); for (i = 0; i < lim; ++i) x[i] = 1ll * x[i] * inv % P; } } int A[N], B[N], C[N]; char a[N], b[N]; int main() { register int i, lim(1), n; scanf("%s", &a); n = strlen(a); for (i = 0; i < n; ++i) A[i] = a[n - i - 1] - '0'; while (lim < (n << 1)) lim <<= 1; scanf("%s", &b); n = strlen(b); for (i = 0; i < n; ++i) B[i] = b[n - i - 1] - '0'; while (lim < (n << 1)) lim <<= 1; for (i = 0; i < lim; ++i) r[i] = (i & 1) * (lim >> 1) + (r[i >> 1] >> 1); ntt(A, lim, 1); ntt(B, lim, 1); for (i = 0; i < lim; ++i) C[i] = 1ll * A[i] * B[i] % P; ntt(C, lim, -1); int len(0); for (i = 0; i < lim; ++i) { if (C[i] >= 10) len = i + 1, C[i + 1] += C[i] / 10, C[i] %= 10; if (C[i]) len = max(len, i); } while (C[len] >= 10) C[len + 1] += C[len] / 10, C[len] %= 10, len++; for (i = len; ~i; --i) putchar(C[i] + '0'); puts(""); return 0; } |
build本页面最近更新:,更新历史
edit发现错误?想一起完善? 在 GitHub 上编辑此页!
people本页面贡献者:
copyright本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用