前言
KOI里发现一个我连暴力都不会打的题可以NTT水80分
于是我就下定决心学一手NTT,顺便复习FFT
主要都是推多项式啦
一些关于NTT的东西
其实NTT也很简单,和FFT差不多
为什么需要NTT呢,因为FFT带了三角函数和浮点数运算,精度误差有时候会比较大
而且对于取模的时候,需要搞个任意膜(膜myy),精度误差更大
所以就出现了NTT
关联
在FFT中,我们有一个欧拉函数e−2πi/ne−2πi/n
我们知道,这个玩意叫n次单位复数根。他有折半,消去引理
如果要在自然界找一个能替代这玩意的东西,相当于这个东西也满足折半,消去引理
幸运的是我们还真的找到了一个(又多了一个要学的算法幸运个啥)
在模P意义下,有e−2πi/n=gp−1/ne−2πi/n=gp−1/n,其中g表示p的原根
什么意思?意思就是,我们把n次单位复数根换成上面的第二个式子,就是NTT了
在逆FFT的情况下,我们要取e−1e−1作为底数,那么在NTT中,只需要取g的逆元即可,最后除len的情况也是一样的
LL pow_mod(LL a,int b,LL mod)
{
LL ans=1LL%mod;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;b>>=1;
}
return ans;
}
void NTT(LL *y,int len,int op)
{
for(int i=0;i<len;i++)if(i<R[i])swap(y[i],y[R[i]]);
for(int i=1;i<len;i<<=1)
{
LL wn=pow_mod(3,(MOD-1)/(i*2),MOD);if(op==-1)wn=pow_mod(wn,MOD-2,MOD);
for(int j=0;j<len;j+=(i<<1))
{
LL w=1;
for(int k=0;k<i;k++)
{
LL u=y[j+k],v=w*y[j+k+i]%MOD;
y[j+k]=(u+v)%MOD;
y[j+k+i]=(u-v+MOD)%MOD;
w=w*wn%MOD;
}
}
}
if(op==-1)
{
LL inv=pow_mod(len,MOD-2,MOD);
for(int i=0;i<len;i++)y[i]=y[i]*inv%MOD;
}
}
NTT+快速幂的模板
原根
如果g是P的原根,就是g^(P-1) = 1 (mod P)当且仅当指数为P-1的时候成立.(这里P是素数).
例如求任何一个质数x的任何一个原根,一般就是枚举2到x-1,并检验。有一个方便的方法就是,求出x-1所有不同的质因子p1,p2…pm,对于任何2<=a<=x-1,判定a是否为x的原根,只需要检验a^((x-1)/p1),a^((x-1)/p2),…a^((x-1)/pm)这m个数中,是否存在一个数mod x为1,若存在,a不是x的原根,否则就是x的原根。
int get_root(int s)
{
int q[1100]={0};
for(int i=2;i<s-1;i++)
if((s-1)%i==0)q[++q[0]]=i;
for(int i=2;;i++)
{
bool bk=true;
for(int j=1;j<=q[0];j++)
{
if(pow_mod(i,q[j],s)==1)bk=false;
if(bk==false)break;
}
if(bk==true)return i;
}
return -1;
}
学完了?
真的学完了。。
因为NTT是在FFT上扩展出来的东西
证明与FFT的证明引理类似
本文介绍了NTT(Number Theoretic Transform)与FFT(Fast Fourier Transform)的基本原理及应用。探讨了NTT作为FFT的一种离散化变体,在处理整数运算及避免浮点数精度损失方面的优势。同时给出了NTT的实现代码示例。
1593

被折叠的 条评论
为什么被折叠?



