FFT


#include<iostream>
#include<cmath>

using namespace std;

namespace IO{
	struct INITDEVICE{INITDEVICE(){ios::sync_with_stdio(false);cin.tie(nullptr);}};
	static INITDEVICE ID;
	inline int gc(){return cin.rdbuf()->sbumpc();}
	inline void pc(char c){cout.rdbuf()->sputc(c);}
	template<typename T>void rd(T &x){
		x=0;int f=1,c=gc();
		while('0'>c||c>'9'){
			if(c==EOF){cerr<<"IE\n";exit(EXIT_FAILURE);}
			if(c=='-')f*=-1;
			c=gc();
		}while('0'<=c&&c<='9'){
			x=x*10+c-'0';
			c=gc();
		}x*=f;
	}
	template<typename T>void wt(T x){
		if(x<0)pc('-');
		static int d,tp,stk[40];
		tp=0;
		do{
			d=x%10;
			stk[++tp]=(d<0?-d:d)+'0';
			x/=10;
		}while(x);
		while(tp)pc(stk[tp--]);
	}
}using namespace IO;


typedef long long ll;
typedef double db;
typedef long double ld;

constexpr int N=4e6+5;
const db pi=acos(-1);

struct cplx{db x,y;};
inline cplx operator +(const cplx& A,const cplx& B){return cplx{A.x+B.x,A.y+B.y};}
inline cplx operator -(const cplx& A,const cplx& B){return cplx{A.x-B.x,A.y-B.y};}
inline cplx operator *(const cplx& A,const cplx& B){return cplx{A.x*B.x-A.y*B.y,A.x*B.y+A.y*B.x};}

struct poly{
	cplx p[N];
	int deg;
}f,g;

int len=1;
int rev[N];//i在二进制表示下倒过来得到的数字,因为这是迭代版fft(位逆序)
/*
为什么一定是位逆序?
因为每次“按奇偶拆”看的是下标的最低位:

最低位是 0 → 去偶数组;

最低位是 1 → 去奇数组。

那么显然,每次分组相当于一次排序(类似基数排序),原下标是高位为第一关键字升序排序的,
而新的下标是以低位为第一关键字排序的。
所以将位逆序直接符合要求
*/

void fft(poly &a,int ind){
	for(int i=0;i<len;++i){
		if(i<rev[i]){//是对称的,保证只交换一次
			swap(a.p[i],a.p[rev[i]]);
		}
	}
	for(int sublen=1;sublen<len;sublen<<=1){
		cplx wn={cos(pi/sublen),sin(pi/sublen)*ind};//欧拉公式
		for(int i=0;i<len;i+=(sublen<<1)){
			cplx wk={1,0};
			for(int j=0;j<sublen;++j,wk=wk*wn){
				cplx x=a.p[i+j],y=wk*a.p[i+sublen+j];
				a.p[i+j]=x+y;
				a.p[i+sublen+j]=x-y;
			}
		}
	}
}

inline void global(){

}

namespace tqy{
	inline void init(){
        rd(f.deg);   
        rd(g.deg);
		for(int i=0;i<=f.deg;++i){
			rd(f.p[i].x);
		}
		for(int i=0;i<=g.deg;++i){
			rd(g.p[i].x);
		}   
	}
	inline void solve(){
		int k=0;
		while(len<=f.deg+g.deg)len<<=1,++k;
		for(int i=0;i<len;++i){
			rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
		}
		fft(f,1);
		fft(g,1);
		for(int i=0;i<len;++i){
			f.p[i]=f.p[i]*g.p[i];
		}
		fft(f,-1);
		for(int i=0;i<=f.deg+g.deg;++i){
			wt(int(f.p[i].x/len+0.5)),pc(' ');//+0.5等价于四舍五入
		}
		pc('\n');

	}
}

signed main(){
	global();
	int T=1;
	while(T--)tqy::init(),tqy::solve();
	return 0;
}
/*

*/

初学FFT的话1可以看洛谷收藏夹命令方块作的文章,讲的挺细致的

posted @ 2026-10-26 21:13  tqytql  阅读(9)  评论(2)    收藏  举报