快速数论变换(FNT)是环 $\mathbb{Z}/ m \mathbb{Z}$ 上的 Fourier 变换(FFT)。
至于 快速 Fourier 变换是怎样的有什么用处,这里就不多说了,可参考这里。
NFT 的核心问题
无论是 FNT 还是 FFT 其本质其关键就是寻找一个 $w$ 使得 $w^{2^n} = 1$。在复数域中这个问题是显然的,而在一个环那就不那么简单了,这里我们考虑环 $R = \mathbb{Z}/ m \mathbb{Z}$。$R$ 为域当且仅当 $m$ 为素数。我们的问题是
- 我们选取 $R$ 中找比较大(满足我们的需求)的 $n$ 使得 $w^{2^n} = 1$ ;
- 找出对应的“原根“;
- 类似 FFT 的处理
- 应用时各种可能出错的情形,最常见的是溢出,还有只适用于数据范围不超过P的非负整数。
NFT 问题解决
为使得分析问题更为简单,我们考虑在$m = p$ 为素数的情形,此时,我们有 $2^n \mid p-1$ 即 $p=k 2^n+1$ 为(Fermat)素数,例如:
- $p=479 \times 2^{21} +1 = 1004535809,g = 3$
- $p= 13 \times 2^{20} + 1 = 13631489,g = 15$
- $p= 17 \times 2^{27} + 1 = 2281701377,g=3$
更多常数选择可见这里。
最终我们选择了 $FM = 1004535809$ 它的优势在于,它的两倍不超过 int 它的乘积不超过 long long 很有利于我们的运算,如果使用刚好不超过 long long 的数使用时很容易出现溢出并不方便。并且它恰好比较大。避免了做完 FFT 出现溢出。另外它可以取到的最大的 $N>2e6$ 也很不错。例如现在如果我们要做 $2^k,k \leq 21$ 的 NFT。那么我们取 $w = g^{\frac{p-1}{2^k}}$ 即可。
HDU 1402
1 | /*------ Welcome to visit blog of dna049: http://dna049.com ------*/ |