[數學/多項式] FFT學習筆記

大佬博客

板子

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
inline int in{
	int i=0,f=1;char ch=0;
	while(ch!='-'&&!isdigit(ch)) ch=getchar();
	if(ch=='-') ch=getchar(),f=-1;
	while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
	return i*f;
}

const int NNN=1e7+5;
const double pi=acos(-1);
int n,m,rot[NNN];
struct Complex{
	double x,y;
	Complex(double _x=0,double _y=0){x=_x,y=_y;}
	friend inline Complex operator + (const Complex u,const Complex v){return Complex(u.x+v.x,u.y+v.y);}
	friend inline Complex operator - (const Complex u,const Complex v){return Complex(u.x-v.x,u.y-v.y);}
	friend inline Complex operator * (const Complex u,const Complex v){return Complex(u.x*v.x-u.y*v.y,u.x*v.y+v.x*u.y);}
}A[NNN],B[NNN],C[NNN];

inline void FFT(Complex *f,int lim,int sgn){
	for(int i=0;i<lim;++i)
		if(i<rot[i]) swap(f[i],f[rot[i]]);
	for(int siz=2;siz<=lim;siz<<=1){
		int len=siz>>1;
		Complex wn(cos(2*pi/siz),sgn*sin(2*pi/siz));
		for(int l=0;l<lim;l+=siz){
			Complex w(1,0);
			for(int i=l;i<l+len;++i){
				Complex tmp=w*f[i+len];
				f[i+len]=f[i]-tmp;
				f[i]=f[i]+tmp;
				w=w*wn;
			}
		}
	}
}

signed main(){
	n=in,m=in;
	for(int i=0;i<=n;++i) A[i].x=in;
	for(int i=0;i<=m;++i) B[i].x=in;
	int lim=1;
	while(lim<=n+m) lim<<=1;
	for(int i=0;i<lim;++i) rot[i]=((rot[i>>1]>>1)|((i&1)?lim>>1:0));
	FFT(A,lim,1);
	FFT(B,lim,1);
	for(int i=0;i<=lim;++i) C[i]=A[i]*B[i];
	FFT(C,lim,-1);
	for(int i=0;i<=m+n;++i) printf("%lld ",(int)(C[i].x/lim+0.49));
	return 0;
}

註釋版

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
inline int in{
	int i=0,f=1;char ch=0;
	while(ch!='-'&&!isdigit(ch)) ch=getchar();
	if(ch=='-') ch=getchar(),f=-1;
	while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
	return i*f;
}

const int NNN=1e7+5;
const double pi=acos(-1);
int n,m,rot[NNN];
struct Complex{
	double x,y;
	Complex(double _x=0,double _y=0){x=_x,y=_y;}
	friend inline Complex operator + (const Complex u,const Complex v){return Complex(u.x+v.x,u.y+v.y);}
	friend inline Complex operator - (const Complex u,const Complex v){return Complex(u.x-v.x,u.y-v.y);}
	friend inline Complex operator * (const Complex u,const Complex v){return Complex(u.x*v.x-u.y*v.y,u.x*v.y+v.x*u.y);}
}A[NNN],B[NNN],C[NNN];

inline void FFT(Complex *f,int lim,int sgn){
	for(int i=0;i<lim;++i)
		if(i<rot[i]) swap(f[i],f[rot[i]]);//迭代,一步到位 
	for(int siz=2;siz<=lim;siz<<=1){//合併項數 
		int len=siz>>1;//合併區間半長度 
		Complex wn(cos(2*pi/siz),sgn*sin(2*pi/siz));//合併siz項,用siz次單位根 
		for(int l=0;l<lim;l+=siz){//區間起點 
			Complex w(1,0);
			for(int i=l;i<l+len;++i){
				Complex tmp=w*f[i+len];
				f[i+len]=f[i]-tmp;
				f[i]=f[i]+tmp;
				w=w*wn;
			}
		}
	}
}

signed main(){
	n=in,m=in;
	for(int i=0;i<=n;++i) A[i].x=in;
	for(int i=0;i<=m;++i) B[i].x=in;
	int lim=1;
	while(lim<=n+m) lim<<=1;//得到2的整次冪 
	for(int i=0;i<lim;++i) rot[i]=((rot[i>>1]>>1)|((i&1)?lim>>1:0));//注意運算優先級,多打括號 
	FFT(A,lim,1);
	FFT(B,lim,1);
	for(int i=0;i<=lim;++i) C[i]=A[i]*B[i];
	FFT(C,lim,-1);
	for(int i=0;i<=m+n;++i) printf("%lld ",(int)(C[i].x/lim/*注意除數*/+0.49));//得到準確值 
	return 0;
}

Tips:

  • for(int i=0;i<=lim;++i) C[i]=A[i]*B[i];爲例:注意範圍
    lim範圍內FFT,點值就有lim+1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章