CNTT

自己口胡版:就是在 \(\mathbf{Z}_p[\sqrt g]\) 上做 NTT,\(g\)\(p\) 的二次非剩余。

原版:就是在 \(\mathbf{Z}_p[\sqrt{-1}]\) 上做 NTT。要求 \(-1\)\(p\) 的二次非剩余。

感兴趣的可以看看提交记录

两者均被 MTT 吊打。推销 128MTT


黑历史,慎点

前言

在oi wiki上看到了CNTT后,一直不明白它的原理,看完原论文后发现自己好像推了个假的CNTT(

原理

在 CNTT 中,用 \(a+bi\) 代表一个复数,其中实部和虚部分别对 \(p\) 取模,\(p \in \mathbb{P}\)。(\(\mathbb{P}\) 为素数集)

注意,这里的 \(i^2\) 不一定是 \(-1\),只要满足 \(i^2\) 为模 \(p\) 意义下的一个二次非剩余即可。

下面证明,\(\{a+bi\}\) 模 p 下构成一个数域。(upd:然而 FFT 不一定要在数域里做)

只证一下乘法逆元。

逆元:对 \(x = a+bi\),其中 \(a \not= 0 \vee b \not= 0\),设其逆元为 \(y=c+di\),由 \(xy=1\) 可知

\[\left\{ \begin{aligned} ac+bdi^2 &= 1 & (1)\\ bc+ad &= 0 & (2) \end{aligned} \right.\]

\(b \not= 0\) 时:由 \((2)\)\(c = -adb^{-1}\),代入 \((1)\) 中可得 \(d = (bi^2-b^{-1}a^2)^{-1}\)

\(bi^2-b^{-1}a^2 \equiv 0 \pmod p\),则 \(i^2 \equiv (ab^{-1})^2 \pmod p\),这与 \(i^2\) 是模 \(p\) 意义下的一个二次非剩余矛盾,所以 \(d\) 一定存在。

\(a \not= 0\) 时,用相似的方法可以推出 \(x^{-1} = y\) 一定存在。

方法

这个数域的大小是 \(p^2\),只要用一些方法找出 \(g = a+bi,g^{(p^2-1)/2} \equiv -1 \pmod p\),则 \(g\) 就是我们要找的 \(p^2-1\) 次“原根”,剩下的和 NTT 类似。

\(p=n\cdot2^k+1\) 时(\(p\) 为 NTT 模数),用 CNTT 可以将最大变换长度翻倍;

\(p=n\cdot2^k-1\) 时,用 CNTT 后最大变换长度能取到 NTT 模数级别。

性能

某谷的提交记录显示,CNTT常数是普通NTT的3倍左右(无读入优化等的情况下),甚至不如FFT。

复数相乘要做 \(4\) 次普通乘法,常数能不大吗

CNTT(O2) 4.56s / 56.52MB / 2.14KB C++14 (GCC 9) O2
CNTT 4.61s / 56.51MB / 2.14KB C++14 (GCC 9)
NTT 1.67s / 32.57MB / 1.69KB C++14 (GCC 9)
FFT 1.99s / 104.60MB / 1.56KB C++14 (GCC 9)

这里CNTT的模数是 \(998244353\),使用 \(j^2=3\)\(2^{24}\) 次单位根选用 \(0+125038983j\)

FFT 有三次变两次优化,CNTT也能用,优化后的测评结果:

FFT 1.37s / 40.46MB / 1.53KB C++14 (GCC 9)
CNTT 1.98s / 24.45MB / 2.27KB C++14 (GCC 9)

优化完的 CNTT 快了不少,FFT 更是反杀 NTT。

posted @ 2023-04-02 10:48  383494  阅读(32)  评论(0编辑  收藏  举报