在算法竞赛和密码学中,NTT算法(Number Theoretic Transform,数论变换)是一种用于高效计算两个整系数多项式乘积的重要工具。它是FFT(快速傅里叶变换)在模意义下的替代方案,特别适用于需要结果对某个质数取模的场景。
本教程将从零开始,用通俗易懂的方式讲解C++实现 NTT 的全过程,即使你是编程小白,也能轻松理解并掌握这一强大算法。
NTT 是 FFT 在有限域(模素数)中的类比。它利用模意义下的“单位根”来实现类似于复数域中 FFT 的分治策略,从而将多项式乘法的时间复杂度从 O(n²) 降低到 O(n log n)。
使用 快速数论变换 的前提是模数 p 必须满足:p = k × 2ⁿ + 1(即 p-1 能被足够大的 2 的幂整除),这样才能保证存在足够多的“原根”作为单位根。
常见的 NTT 模数包括:
以 998244353 为例,它满足 998244353 = 119 × 2²³ + 1,因此最多可处理长度为 2²³ 的多项式。
我们将逐步实现以下功能:
long long qpow(long long a, long long b, long long mod) { long long res = 1; while (b) { if (b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res;} const long long MOD = 998244353;const long long G = 3; // 原根void ntt(vector<long long> &a, bool invert) { int n = a.size(); // 位逆序重排 for (int i = 1, j = 0; i < n; i++) { int bit = n >> 1; for (; j & bit; bit >>= 1) j ^= bit; j ^= bit; if (i < j) swap(a[i], a[j]); } for (int len = 2; len <= n; len <<= 1) { long long wlen = qpow(G, (MOD - 1) / len, MOD); if (invert) wlen = qpow(wlen, MOD - 2, MOD); // 逆元 for (int i = 0; i < n; i += len) { long long w = 1; for (int j = 0; j < len / 2; j++) { long long u = a[i + j]; long long v = a[i + j + len / 2] * w % MOD; a[i + j] = (u + v) % MOD; a[i + j + len / 2] = (u - v + MOD) % MOD; w = w * wlen % MOD; } } } if (invert) { long long inv_n = qpow(n, MOD - 2, MOD); for (long long &x : a) x = x * inv_n % MOD; }} vector<long long> multiply(vector<long long> const& a, vector<long long> const& b) { vector<long long> fa(a.begin(), a.end()), fb(b.begin(), b.end()); int n = 1; // 找到大于等于 a.size() + b.size() - 1 的最小 2 的幂 while (n < (int)(a.size() + b.size())) n <<= 1; fa.resize(n); fb.resize(n); ntt(fa, false); ntt(fb, false); for (int i = 0; i < n; i++) fa[i] = fa[i] * fb[i] % MOD; ntt(fa, true); // 截断多余项 fa.resize(a.size() + b.size() - 1); return fa;} 下面是一个完整的 C++ 程序,演示如何使用上述函数计算两个多项式的乘积:
#include <iostream>#include <vector>#include <algorithm>using namespace std;// 此处插入 qpow、ntt、multiply 函数int main() { vector<long long> a = {1, 2, 3}; // 表示 1 + 2x + 3x² vector<long long> b = {2, 1}; // 表示 2 + x vector<long long> c = multiply(a, b); // 结果应为 2 + 5x + 7x² + 3x³ for (long long x : c) cout << x << " "; cout << endl; return 0;} 通过本教程,我们详细讲解了 NTT算法 的原理及其在 C++实现 中的关键步骤。NTT 是处理模意义下 多项式乘法 的利器,尤其在算法竞赛中应用广泛。掌握 快速数论变换 不仅能提升你的编程能力,还能为你解决更复杂的数学问题打下坚实基础。
建议你动手敲一遍代码,并尝试修改输入多项式,观察输出结果是否符合预期。实践是掌握算法的最佳方式!
本文由主机测评网于2025-12-16发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025128533.html