テンプレート-高速フーリエ変換(反復バージョン)

#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

const double PI = acos(-1);		//PI
const int 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) {
    
     return Complex(a.R + b.R, a.I + b.I); }
Complex operator-(Complex a, Complex b) {
    
     return Complex(a.R - b.R, a.I - b.I); }
Complex operator*(Complex a, Complex b) {
    
     return Complex(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,右边是开区间。
void FFT(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次单位根
			}
		}
	}
}
int main() {
    
    

	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) << " ";		//四舍五入
	}
	return 0;
}

おすすめ

転載: blog.csdn.net/qq_45739057/article/details/105713220