多项式乘法 快速傅里叶变换(FFT)
前置知识1
1.多项式:一个以为变量的多项式定义在一个代数域上,将函数表示为形式和:
2.多项式的系数表示法;即由多项式的系数组成的向量
2.多项式的点值表示法:即一个由的点组成的集合
其中满足对于
3.点值表示法的多项式乘法:
已知两个多项式的点值表示:
则两式相乘后的点值表示为:
4.;离散傅里叶变换(DFT):我们称向量 为向量 的离散傅里叶变换,记为 , 同时,
快速傅里叶变换(FFT):
可以在的时间复杂度内求解两个次数界为的多项式的乘法。算法主要由三步构成:
1.求值:将多项式由系数表示法转化为点值表示法,即。
2.点值乘法:将两个多项式的点值相乘,得到所求多项式的点值表达式。
3.插值:将所求多项式由点值表示法转变为系数表示法,即。
一个次数界为和的多项式相乘,需要个点的点值表达式,朴素的求法为,显然的取值是任意的,我们可以通过选取特殊的来降低求值的复杂度。
n次单位复数根:
是指满足的复数,共有n个,分别为
根据欧拉公式可得:
n次单位复数根有几个性质:
性质1:
性质2:
性质3: 对任意和不能被整除的非负整数,有:
FFT的过程:
1.求值
(以下假定n为2的整数次幂)
对于多项式
将其按照奇偶项拆分:
则:
求在处的值,即为求和在处的值。
根据性质1可得:,因此这n个单位复数根仅是由个不同的值组成的,我们可以先求出这个值,再根据性质2,求出后一半的值,于是问题的规模缩小了一半,使用分治的方法即可在的时间内求值。
2.插值
将的过程写成矩阵乘法的形式,则可得
其中为时的范德蒙德矩阵。则:
根据范德蒙德矩阵的性质,易得的处的元素为 则可知:
式子与上面求值的相似,通过类似方法也可以在的时间内插值。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long lld;
const int N = 1000005;
const double PI = acos(-1);
typedef complex <double> comp;
void FFT(int M, vector <comp> &a, int typ) {
if(M == 1) return ;
vector <comp> a1(M / 2 + 2), a2(M / 2 + 2);
int cnt = 0;
for(int i = 0; i <= M; i += 2) {
a1[cnt] = a[i]; a2[cnt++] = a[i + 1];
}
FFT(M >> 1, a1, typ); FFT(M >> 1, a2, typ);
comp wn(cos(PI * 2 / M), typ * sin(PI * 2 / M)), w(1, 0);
for(int i = 0; i < (M >> 1); i++) {
a[i] = a1[i] + w * a2[i];
a[i + (M >> 1)] = a1[i] - w * a2[i];
w = w * wn;
}
}
int n, m, M;
int main() {
// freopen("data.in", "r", stdin);
cin >> n >> m;
M = 1; while(M <= n + m) M <<= 1;
vector <comp> a(M + 2), b(M + 2);
for(int i = 0; i <= n; i++) {
double x; cin >> x;
a[i] = complex <double> (x, 0);
}
for(int i = 0; i <= m; i++) {
double x; cin >> x;
b[i] = complex <double> (x, 0);
}
int M = 1; while(M <= n + m) M <<= 1;
FFT(M, a, 1); FFT(M, b, 1);
vector <comp> c(M + 2);
for(int i = 0; i <= M; i++) {
c[i] = a[i] * b[i];
}
FFT(M, c, -1);
for(int i = 0; i <= n + m; i++) {
cout << (int)(c[i].real() / M + 0.5) << " ";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下