#include<cmath>#include<iostream>#include<algorithm>usingnamespace std;constdouble PI =acos(-1);//PIconstint N =1e6+10;//复数结构体struct Complex {double R, I;//R : 复数的实部。I : 复数的虚部。Complex(){ R =0.0, I =0.0;}Complex(double r,double i):R(r),I(i){}};
Complex F[N], G[N];//重载操作符 包含复数的加减乘
Complex operator+(Complex a, Complex b){returnComplex(a.R + b.R, a.I + b.I);}
Complex operator-(Complex a, Complex b){returnComplex(a.R - b.R, a.I - b.I);}
Complex operator*(Complex a, Complex b){returnComplex(a.R * b.R - a.I * b.I, a.R * b.I + a.I * b.R);}int rev[N], len, lim =1;//len表示二进制的最大位数//lim表示次数界,rev位逆序置换后的数组//FFT中的for循环只有第一个是[1,log2(lim)],其余都是左边为0,右边是开区间。voidFFT(Complex* a,int opt){//opt == 1 进行快速傅里叶 opt == -1 进行逆快速傅里叶for(int i =0; i < lim; i++)if(i < rev[i])swap(a[i], a[rev[i]]);//位逆序置换for(int dep =1; dep <=log2(lim); dep++){//遍历的层数int n =1<< dep;//合并后序列的长度
Complex wn =Complex(cos(2.0* PI / n), opt *sin(2.0* PI / n));//旋转因子是和合并后序列的长度有关的for(int k =0; k < lim; k += n){//对每隔n的长度的数列进行蝴蝶操作
Complex w =Complex(1,0);for(int j =0; j < n /2; j++){//遍历长度的一半
Complex t = w * a[k + j + n /2];//蝴蝶操作
Complex u = a[k + j];//蝴蝶操作
a[k + j]= u + t;
a[k + j + n /2]= u - t;
w = w * wn;//求出主n次单位根}}}}intmain(){int n, m;
cin >> n >> m;for(int i =0; i <= n; i++) cin >> F[i].R;//将两个多项式存在两个复数数组的实部中for(int i =0; i <= m; i++) cin >> G[i].R;while(lim <= n + m) lim <<=1, len++;//扩展次数 快速傅里叶只能处理次数界为2的n次方的多项式//只需找到大于n + m的最小满足2的len次方的数for(int i =1; i < lim; i++){
rev[i]=(rev[i >>1]>>1)|((i &1)<<(len -1));//位逆序置换的递推式}FFT(F,1),FFT(G,1);//分别将两个多项式变为点值表示for(int i =0; i <= lim; i++){
F[i]= F[i]* G[i];//点值表示法的多项式的乘法就是纵坐标相乘,即两复数相乘}FFT(F,-1);//进行逆快速傅里叶,将点值表示法变为系数表示法for(int i =0; i <= n + m; i++){
cout <<(int)(F[i].R /(double)lim +0.5)<<" ";//四舍五入}return0;}