快速数论变换总结

前置

根据快速傅里叶变换,可以在 Θ(nlogn) 的时间计算卷积。但是由于用到了复数及三角函数,具有精度误差,且不方便取模。

于是考虑快速傅里叶变换在数论上的实现,避免了精度误差,支持了取模运算。

引入概念原根

定义

由欧拉定理可知,对 aZmN(a,m)=1aφ(m)1(modm)

因此满足同余式 an1(modm) 的最小正整数 n 存在,这个 n 称作 a 模 m 的阶,记作 δm(a)ordm(a)

性质

a,a2,,aδm(a)m 两两不同余。

an1(modm),则 δm(a)n

原根

定义

mNgZ。 若 (g,m)=1,且 δm(g)=φ(m),则称 g 为模 m 的原根。

g 满足
δm(g)=|Zm|=φ(m)。当 m 是质数时,我们有 gimodm,0<i<m 的结果互不相同。

性质

g 是模 p 的原根,gnk=gp1nk

指数性

gnkgnmgp1nkgp1nmgnk+m(modp)

周期性

gnkgnk×1gnkgnφ(p)gnkgnp1gnkgnngnn+k(modp)

对称性

由阶的性质与:

(gnn2)2gnn1(modp)

可得:

gnk+n2gnk(modp)

折半性

gn2kgp1n2kgp1n2gn2k(modp)

可以观察到原根与复数在这里是完全等价的,故只需将快速傅里叶变换的复数部分替换为原根即可。

NTT & INTT

void NTT(ll f[],int n,int op)
{
    if(n==1) return;
    ll f1[n/2],f2[n/2];
    for(int i=0;i<n/2;++i)
    {
        f1[i]=f[i<<1],f2[i]=f[i<<1|1];
    }
    NTT(f1,n>>1,op),NTT(f2,n>>1,op);
    ll gk=1,g1=qpow(op==1?g:gi,(p-1)/n);
    for(int i=0;i<n/2;++i)
    {
        f[i]=(f1[i]+gk*f2[i]%p)%p;
        f[i+n/2]=(p+f1[i]-gk*f2[i]%p)%p;
        gk=gk*g1%p;
    }
}

本文作者:vanueber

本文链接:https://www.cnblogs.com/vanueber/p/18678787

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   vanueber  阅读(9)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起