【笔记】快速傅里叶变换(FFT)


OI-Wiki

#include 
#include 
#include 
//#include 
using namespace std;
const double Pi = acos(-1);
//typedef complex Comp;
const int MAXN = 3000006;
struct Comp {
	double x, y;
	Comp(double _x=0.0, double _y=0.0) {
		x = _x, y = _y;
	}
	Comp operator-(const Comp &b) const {
		return Comp(x-b.x, y-b.y);
	}
	Comp operator+(const Comp &b) const {
		return Comp(x+b.x, y+b.y);
	}
	Comp operator*(const Comp &b) const {
		return Comp(x*b.x-y*b.y, x*b.y+y*b.x);
	}
};
struct _FFT {
	int rev[MAXN];
	void change(Comp y[], int len) // len = 2^k
	{
		rev[0] = 0;
		for (int i=1; i< len; i++) {
			rev[i] = rev[i>>1]>>1;
			if (i&1) rev[i] |= len>>1;
		}
		for (int i=0; i< len; i++) if (i< rev[i]) swap(y[i], y[rev[i]]);
	}
	void fft(Comp y[], int len, int on) // on = 1 DFT, on = -1 IDFT
	{
		change(y, len);
		for (int h=2; h<=len; h<<=1) {
			Comp wn(cos(2*Pi/h), sin(on*2*Pi/h));
			for (int j=0; j< len; j+=h) {
				Comp w(1, 0); // w_n^k
				for (int k=j; k< j+(h>>1); k++) {
					Comp u = y[k], t = w*y[k+(h>>1)];
					y[k] = u + t, y[k+(h>>1)] = u - t;
					w = w * wn;
				}
			}
		}
		if (on==-1) for (int i=0; i< len; i++) y[i].x /= len;
	}
} FFT;
Comp F[MAXN], G[MAXN];
int main()
{
	int N, M; scanf("%d%d", &N, &M); N++, M++; // 0...N-1
	int len = 1; double a;
	while (len< (N<<1) || len< (M<<1)) len <<= 1;
	for (int i=0; i< N; i++) scanf("%lf", &a), F[i] = Comp(a, 0);
	for (int i=N; i< len; i++) F[i] = Comp(0, 0);
	for (int i=0; i< M; i++) scanf("%lf", &a), G[i] = Comp(a, 0);
	for (int i=M; i< len; i++) G[i] = Comp(0, 0);
	FFT.fft(F, len, 1), FFT.fft(G, len, 1);
	for (int i=0; i< len; i++) F[i] = F[i] * G[i];
	FFT.fft(F, len, -1);
	for (int i=0; i< N+M-1; i++) printf("%d ", (int)(F[i].x+0.5));
}