花了N久时间,终于把这个难啃的骨头啃下来了。
建议大家学习fft时,千万不要到网上找各种快速傅里叶变换的解释,那实在是令人难以理解。
可以查阅《算法导论》并结合洛谷模板里的题解,可以深入理解多项式乘法的算法。
这里是一个可以用的板子。
#include<iostream> #include<cstdio> #include<climits> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;i++) #define dep(i,a,b) for(int i=a;i>=b;i--) const int M=3e6; struct cp{//最好手打一遍复数complex类型,反正也就几行 double x,y; cp(double xx=0,double yy=0){ x=xx;y=yy; } cp operator+(const cp&a){ return cp(x+a.x,y+a.y); } cp operator-(const cp&a){ return cp(x-a.x,y-a.y); } cp operator*(const cp&a){ return cp(x*a.x-y*a.y,x*a.y+y*a.x); } }a[M],b[M]; int r[M]; int limit=1,l=0; void fft(cp*a,int f){//不理解的话——背!代!码! rep(i,0,limit-1)if(i<r[i])swap(a[i],a[r[i]]); for(int mid=1;mid<limit;mid<<=1){ cp wn(cos(M_PI/mid),f*sin(M_PI/mid));//单位根 for(int j=0,R=mid<<1;j<limit;j+=R){ cp w(1,0); for(int k=0;k<mid;k++,w=w*wn){ cp x=a[j+k],y=w*a[j+mid+k]; a[j+k]=x+y;a[j+mid+k]=x-y; } } } } int main(){ int n,m; scanf("%d%d",&n,&m); rep(i,0,n)scanf("%lf",&a[i].x); rep(i,0,m)scanf("%lf",&b[i].x); while(limit<=n+m)limit<<=1,l++; l--; rep(i,0,limit-1)r[i]=(r[i>>1]>>1)|((i&1)<<l); fft(a,1);fft(b,1); rep(i,0,limit)a[i]=a[i]*b[i]; fft(a,-1); rep(i,0,n+m)printf("%d ",(int)(a[i].x/limit+0.5)); return 0; }