FFT
其中
2ce=len
无视这个板子,FFT照着NTT写就行了。
w[0]=(1,0)
w[1]=(cos(2*pi/len),sin(2*pi/len))
void DFT(node *a,int sig){
fo(i,0,len-1){
int p=0;
for(int j=0,tp=i;j<ce;j++,tp/=2) p=(p<<1)+(tp%2);
tt[p]=a[i];
}
for(int m=2;m<=len;m*=2){
int half=m/2;
fo(i,0,half-1){
node w;
w.x=cos(i*sig*pi/half),w.y=sin(i*sig*pi/half);
for(int j=i;j<len;j+=m){
node u=tt[j],v=tt[j+half]*w;
tt[j]=u+v;
tt[j+half]=u-v;
}
}
}
if (sig==-1)
fo(i,0,len-1) tt[i].x/=len;
fo(i,0,len-1) a[i]=tt[i];
}
void FFT(node *a,node *b,node *c){
int i;
fo(i,0,len-1) e[i]=a[i],f[i]=b[i];
DFT(e,1);DFT(f,1);
fo(i,0,len-1) e[i]=e[i]*f[i];
DFT(e,-1);
fo(i,0,len-1) c[i]=e[i];
}
NTT
考虑相对于FFT变化的地方。
ce的意义没有变化,其中,w数组需要预处理,
w[i]=w[1]i
ni则表示len关于模数的逆元。
void DFT(int *a,int sig){
int i;
fo(i,0,len-1){
int p=0;
for(int j=0,tp=i;j<ce;j++,tp/=2) p=(p<<1)+(tp%2);
tt[p]=a[i];
}
for (int m=2;m<=len;m*=2){
int half=m/2,bei=len/m;
fo(i,0,half-1){
int wi=sig>0?w[i*bei]:w[len-i*bei];
for(int j=i;j<len;j+=m){
int u=tt[j],v=(ll)tt[j+half]*wi%mo;
tt[j]=(u+v)%mo;
tt[j+half]=(u-v)%mo;
}
}
}
if (sig==-1)
fo(i,0,len-1) tt[i]=(ll)tt[i]*ni%mo;
fo(i,0,len-1) a[i]=tt[i];
}
void NTT(int *a,int *b,int *c){
int i;
fo(i,0,len-1) A[i]=a[i],B[i]=b[i];
DFT(A,1);DFT(B,1);
fo(i,0,len-1) A[i]=(ll)A[i]*B[i]%mo;
DFT(A,-1);
fo(i,0,len-1) c[i]=A[i];
}
预处理部分
len=1;
while (len<=n*2) len*=2;
ni=quicksortmi(len,mo-2);
ce=(db)log(len)/log(2);
w[0]=1;
w[1]=quicksortmi(GG,(mo-1)/len);
fo(i,2,len) w[i]=(ll)w[i-1]*w[1]%mo;
GG表示模数的一个原根