学习NTT(快速数论变换)小记

前言

以前一直知道FFT的这个思想,一直没有实现。
本想着转C语言抛弃P语言后就码一码。
但最近遇到了奇怪的题目,要用到NTT。
于是就学了一发,借着各种板子好歹是学会了。

简介

NTT是什么?
其实就是FFT,一样是求多项式卷积之类的东东。只不过没有利用到复数里面单位根的性质。
有什么用?
可以实现取模操作!

具体操作

原根:

百度百科的欧拉函数比较费解。
其实解释起来就是对于一个数P
g是它的原根当且仅当g满足:
x(0<=x<P1)gxmod P对于任意的x(0<=x<P-1)g^xmod\ P互不相同
根据这个玩意儿,很容易判断出一个数g是不是P的原根。
显然:当P是一个质数时,一定有原根。
对于原根,都比较难找(只能暴力),但对于一个质数的原根,都很小。
比如998244353,1004535809,469762049这三个数的原根为3.

原根的用处:

我们看到之前FFT里面的单位根:ωni\omega_n^i
我们直接把上面这个单位根替换成原根即可。
怎么替换?
ωni=gi(mo1)nmo\omega_n^i=g^{i*\lfloor\frac{(mo-1)}n\rfloor}(mo是模数)
直接套上FFT板子即可。

为什么:

我们知道,FFT是利用单位根的几个重要性质来加速的。
那么换成原根之后,只需要满足单位根那几个性质就可以了。
怎么满足呢?

我们知道,单位根满足:
1、全部都不相同
2、ωnxωny=ωnx+y=ωn(x+y)modn\omega_n^x\omega_n^y=\omega_n^{x+y}=\omega_n^{(x+y)mod n}
然后利用这两个性质推出其他性质。

那么原根是否也可以呢?
1、gi(mo1)ng^{i*\lfloor\frac{(mo-1)}n\rfloor}这个玩意儿右边是一样的,左边的i是不定的。
而且这个g由于是原根,模mo的意义下是都不同的。
得证
2、这个性质其实对模数要求很高。
比如这个模数:1004535809(479 * 2 ^21 + 1)
我们发现,这个模数就很棒,对于一个比较大的n(2的某次方)可以整除。
那么可以容易消去下取整。
接下来就好搞了:
gx(mo1)ngy(mo1)ng^{x*\frac{(mo-1)}n}*g^{y*\frac{(mo-1)}n}
容易变成:
(gx)(mo1)n(gy)(mo1)n(g^x)^{\frac{(mo-1)}n}*(g^y)^{\frac{(mo-1)}n}
(g(x+y))(mo1)n{(g^{(x+y)})}^\frac{(mo-1)}n
已知:
(gn)(mo1)n=gmo1{(g^{n})}^\frac{(mo-1)}n=g^{mo-1}
根据费马小定理:gmo1=1g^{mo-1}=1
所以说:(g(x+y))(mo1)n=(g(x+y)mod n)(mo1)n{(g^{(x+y)})}^\frac{(mo-1)}n={(g^{(x+y)mod\ n})}^\frac{(mo-1)}n
那么就意味着可以利用原根来代替单位根搞了。

其他什么性质就不推了。

应用(板子)

我们发现,NTT与FFT的流程、时间都是一样的。
这玩意似乎很棒,比起FFT有以下优点:
1、可以取模
2、避免FFT的精度问题

但是,有优点也有缺点:
1、模数通常很头疼(为什么可以往下翻)
2、常数大(可能是我不会卡常)

一个套路——通常看到一个卷积的形式并且模数为:998244353,1004535809,469762049时,可以考虑NTT了。

板子放在例题里了,自己去看
洛谷P3803 【模板】多项式乘法(FFT)(话说这题我NTT还TLE了)
JZOJ3303. 【集训队互测2013】城市规划(时限良心)

拓展

有时候NTT模数不得,怎么办?
据说可以利用上面的三个模数搞,搞完后用中国剩余定理。
(据说还有很恶心的题,然鹅我没有做多少)

posted @ 2019-07-07 20:45  RainbowCrown  阅读(398)  评论(1编辑  收藏  举报