快速傅立叶变换(FFT)
FFT的里有许多地方我也搞不懂,我不想懂也不需要懂,知道结论能用就行了。。。看了好多天的鬼东西,本来觉得好难,看完之后觉得也不过如此。
单位复根:
递归的形式:
void FFT(complex<double> a[],int n){
if(n==1) return;
complex<double> *a0=new complex<double>[n/2];
complex<double> *a1=new complex<double>[n/2];
for(int i=0;i<n;i+=2){ //用奇偶次项系数组成新的多项式
a0[i/2]=a[i];
a1[i/2]=a[i+1];
}
FFT(a0,n/2);FFT(a1,n/2); //递归分治问题
complex<double> wn(cos(2*M_PI/n),sin(2*M_PI/n)); //取n次方根
complex<double> w(1,0);
for(int i=0;i<(n/2);i++){ //蝶形操作,由下一层的a[i],a[i+n/2]
a[i]=a0[i]+w*a1[i]; //更新本层的 a[i],a[i+n/2]
a[i+n/2]=a0[i]-w*a1[i];
w=w*wn; //旋转因子
}
return;
}
完整代码:
#include<bits/stdc++.h>
using namespace std;
int a[100];
int b[100];
void FFT(complex<double> a[],int n,int op){
if(n==1) return;
complex<double> *a0=new complex<double>[n/2];
complex<double> *a1=new complex<double>[n/2];
for(int i=0;i<n;i+=2){ //用奇偶次项系数组成新的多项式
a0[i/2]=a[i];
a1[i/2]=a[i+1];
}
FFT(a0,n/2,op);FFT(a1,n/2,op); //递归分治问题
complex<double> wn(cos(2*M_PI/n),sin(2*M_PI*op/n)); //取n次方根
complex<double> w(1,0);
for(int i=0;i<(n/2);i++){ //蝶形操作,由下一层的a[i],a[i+n/2]
a[i]=a0[i]+w*a1[i]; //更新本层的 a[i],a[i+n/2]
a[i+n/2]=a0[i]-w*a1[i];
w=w*wn; //旋转因子
}
return;
}
int main()
{
int m1,m2;
scanf("%d%d",&m1,&m2);
for(int i=0;i<m1;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<m1;i++){
scanf("%d",&b[i]);
}
int n=1;
while(n<m1+m2){ //不能小于两个多项式相乘的长度m1+m2
n<<=1;
}
complex<double> *c=new complex<double> [n+1];
complex<double> *d=new complex<double> [n+1];
for(int i=0;i<m1;i++){
c[i]=complex<double>(a[i],0);
}
for(int i=0;i<m2;i++){
d[i]=complex<double>(b[i],0);
}
FFT(c,n,1); //DFT变换
FFT(d,n,1); //DFT变换
for(int i=0;i<n;i++){
c[i]=c[i]*d[i]; //点值相乘
}
FFT(c,n,-1); //IDFT逆变换
for(int i=0;i<n;i++){
a[i]=(c[i].real()/n+0.5); // n倍结果
}
for(int i=0;i<n;i++){
printf("%d ",a[i]);
}
return 0;
}
/*
测试数据,
输入:
5 5
1 1 0 0 0
1 0 1 1 1
输出:
1 1 1 2 2 1 0 0 0 0 0 0 0 0 0 0
解释:输入数据为高低位颠倒的两个数
(00011) * (11101)= (0000000000122111)
(11) * (11101)= (122111)
*/
注意:
迭代替代递归:
减少一次DFT变换的方式:
尽力优化double精度误差问题:
NNT快速数论变换:
FWT?: