前言
以前一直知道FFT的这个思想,一直没有实现。
本想着转C语言抛弃P语言后就码一码。
但最近遇到了奇怪的题目,要用到NTT。
于是就学了一发,借着各种板子好歹是学会了。
简介
NTT是什么?
其实就是FFT,一样是求多项式卷积之类的东东。只不过没有利用到复数里面单位根的性质。
有什么用?
可以实现取模操作!
具体操作
原根:
百度百科的欧拉函数比较费解。
其实解释起来就是对于一个数P
g是它的原根当且仅当g满足:
根据这个玩意儿,很容易判断出一个数g是不是P的原根。
显然:当P是一个质数时,一定有原根。
对于原根,都比较难找(只能暴力),但对于一个质数的原根,都很小。
比如998244353,1004535809,469762049这三个数的原根为3.
原根的用处:
我们看到之前FFT里面的单位根:
我们直接把上面这个单位根替换成原根即可。
怎么替换?
直接套上FFT板子即可。
为什么:
我们知道,FFT是利用单位根的几个重要性质来加速的。
那么换成原根之后,只需要满足单位根那几个性质就可以了。
怎么满足呢?
我们知道,单位根满足:
1、全部都不相同
2、
然后利用这两个性质推出其他性质。
那么原根是否也可以呢?
1、这个玩意儿右边是一样的,左边的i是不定的。
而且这个g由于是原根,模mo的意义下是都不同的。
得证
2、这个性质其实对模数要求很高。
比如这个模数:1004535809(479 * 2 ^21 + 1)
我们发现,这个模数就很棒,对于一个比较大的n(2的某次方)可以整除。
那么可以容易消去下取整。
接下来就好搞了:
容易变成:
已知:
根据费马小定理:
所以说:
那么就意味着可以利用原根来代替单位根搞了。
其他什么性质就不推了。
应用(板子)
我们发现,NTT与FFT的流程、时间都是一样的。
这玩意似乎很棒,比起FFT有以下优点:
1、可以取模
2、避免FFT的精度问题
但是,有优点也有缺点:
1、模数通常很头疼(为什么可以往下翻)
2、常数大(可能是我不会卡常)
一个套路——通常看到一个卷积的形式并且模数为:998244353,1004535809,469762049时,可以考虑NTT了。
板子放在例题里了,自己去看
洛谷P3803 【模板】多项式乘法(FFT)(话说这题我NTT还TLE了)
JZOJ3303. 【集训队互测2013】城市规划(时限良心)
拓展
有时候NTT模数不得,怎么办?
据说可以利用上面的三个模数搞,搞完后用中国剩余定理。
(据说还有很恶心的题,然鹅我没有做多少)