FFT可以帮助我们快速地将多项式从系数表达变换成点值表达。但由于涉及浮点数运算,我们需要对一些数取模时,不能一边计算一边取模,所以有可能会爆炸。而且我们有时候也会因此丢失精度,导致结果错误。但是NTT是利用一些特殊的模数,基于数论来进行变换,过程中所使用的都是整数,所以不存在这些问题。
阶
对于的整数,满足
的最小整数
,称为
模
的阶。
原根
设是正整数,
是整数,若
模
的阶等于
,则称
为模
的一个原根。
NTT
事实上,在模素数的意义下中,我们可以把
看做是和FFT中
是等价的(
是模
的原根),所以我们就可以把FFT稍微修改一下即可。素数P我们通常使用费马素数
,它的原根是
。常用的模数还有
等。注意:在模意义下的除一个数,应乘上它的逆元。求逆元可以通过费马小定理用快速幂来求。
代码(注意,这里的 是原根,
是原根的逆元):
void NTT(int *a,int limit,int type){
for(int i=0;i<limit;i++)
if(i<r[i])
swap(a[i],a[r[i]]);
for(int mid=1;mid<limit;mid<<=1){
int wn=qpow(type==1?g:gi,(mod-1)/(mid<<1));
for(int i=0;i<limit;i+=(mid<<1)){
int w=1;
for(int j=0;j<mid;j++,w=1ll*w*wn%mod){
int x=a[i+j],y=1ll*w*a[i+j+mid]%mod;
a[i+j]=Add(x,y);
a[i+j+mid]=Minus(x,y);
}
}
}
if(type==-1)
for(int i=0;i<limit;i++)
a[i]=1ll*a[i]*inv[limit]%mod;
return;
}