NTT简单总结
Posted evan704
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NTT简单总结相关的知识,希望对你有一定的参考价值。
NTT简单总结
NTT是一个玄学的东西,它通过数论达到和FFT一样的效果(甚至还要快得多)。
NTT的原理其实是将FFT的$w^k_n$通过另外一个东西代替,从而将FFT中极其之慢的(而且精度爆炸的)浮点数运算更改为整数运算。
在讲NTT之前,先来了解一下数学方面的内容。
数学部分
阶
若$(a,p)$=1,且$p>1$,对于$a^n\\equiv1(mod p)$最小的$n$称为$a$模$p$的阶,记为$\\delta_p(a)$
原根
设正整数$p$,整数$a$,若$\\delta_p(a)=\\phi(p)$则称$a$是模$p$的一个原根
原根有一些有趣的性质,而且跟我们在FFT中用到的单位根用到的性质一样!别问我怎么证
为了避免吐槽,还是放个大佬证明
好的,我们终于将浮点数运算转换到了整数域运算。
所以我们直接将FFT代码中的单位根全部换成原根就阔以了。
(不会FFT的请左转百度或右转我的博客)
代码部分
话说这种算法都应该背模板
#include<iostream> #include<cmath> using namespace std; typedef long long ll; const int N=1e7+5,P=998244353,P1=3,P2=332748118; int lena,lenb,n=1,lim,r[N]; ll a[N],b[N]; ll rpow(ll x,ll y)//要手打 ll res=1; while(y) if(y&1)res=(res*x)%P; x=(x*x)%P; y>>=1; return res%P; inline int read() int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) if(ch==‘-‘)f=-1; ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘; ch=getchar(); return x*f; void NTT(ll *A,int tp) for(int i=0;i<n;i++)if(i<r[i])swap(A[i],A[r[i]]); for(int i=1;i<n;i<<=1) ll W=rpow(tp?P1:P2,(P-1)/(i<<1));//替换成原根 for(int j=i<<1,k=0;k<n;k+=j) ll w=1; for(int l=0;l<i;l++,w=(w*W)%P)//注意模数 int x=A[k+l],y=w*A[k+i+l]%P; A[k+l]=(x+y)%P; A[k+i+l]=(x-y+P)%P; int main() lena=read();lenb=read(); while(n<=lena+lenb)n<<=1,lim++; for(int i=0;i<=lena;i++)a[i]=(read()+P)%P; for(int i=0;i<=lenb;i++)b[i]=(read()+P)%P; for(int i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(lim-1)); NTT(a,1); NTT(b,1); for(int i=0;i<=n;i++)a[i]=(a[i]*b[i])%P; NTT(a,0); ll inv=rpow(n,P-2); for(int i=0;i<=lena+lenb;i++)printf("%d ",(a[i]*inv)%P);
实测洛谷P3803用FFT 3.14s,NTT 1.76s(不吸氧)
(上为NTT,下为FFT)
以上是关于NTT简单总结的主要内容,如果未能解决你的问题,请参考以下文章