FFT(快速傅里叶变换)

FFT(快速傅里叶变换)

前置知识

\(1.复数\)

\(2.单位根\)

\(3.循环结构\)

\(4.C++\)

1.复数

  • \(定义:形如a+bi的数,其中i^2=-1\)
  • \(计算:1.(a+bi)+(c+di)=(a+c)+(b+d)i\)

    \(\ \ \ \ \ \ \ \ \ \ \ 2.(a+bi)-(c+di)=(a-c)+(b-d)i\)

    \(\ \ \ \ \ \ \ \ \ \ \ 3.(a+bi)(c+di)=(ac-bd)+(ad+bc)i\)
  • \(向量表示法\)

    \(用x表示实部(没有i的部分),用y表示虚部(i前的系数)\)

    \(性质1.复数乘法满足向量模角相加\)

    \(证明:arctan(\frac{a}{b})+arctan(\frac{c}{d})=arctan(\frac{\frac{a}{b}+\frac{c}{d}}{1-\frac{ac}{bd}})=arctan(\frac{ad+bc}{bd-ac})\)

    \(是不是巨简单!\)

2.单位根

  • \(定义:n次单位根是n次幂为1的复数。它们位于复平面的单位圆上,\)
    \(构成正n边形的顶点,其中一个顶点是1。\)

  • \(显然,\omega_n^0=\omega_n^n=1,\omega_n=(cos(\frac{2\pi}{n}),sin(\frac{2\pi}{n})),n个复数为\omega_n^1,\omega_n^2...\omega_n^n\)

  • \(性质:\omega_{n}^k=\omega_{2n}^{2k}\)

正题

\(令A(x)=a_0+a_1x^1...a_nx^n\)

\(则A(x)=(a_0+a_2x^2...a_{2\lfloor\frac{n}{2}\rfloor}x^{2\lfloor\frac{n}{2}\rfloor})+(a_1x+a_3x^3...a_{2\lfloor\frac{n}{2}\rfloor+1}x^{2\lfloor\frac{n}{2}\rfloor+1}),令左边的为A_1(x^2),右边的为xA_2(x^2),A(x)=A_1(x^2)+xA_2(x^2)\)



\(将\omega_n^k(k<\frac{n}{2})带入得\)

\(A(\omega_n^k)=A_1(\omega_n^{2k})+\omega_n^kA_2(\omega_n^{2k})\)

\(将\omega_n^{k+\frac{n}{2}}带入得\)

\(A(\omega_n^k)=A_1(\omega_n^{2k})-\omega_n^kA_2(\omega_n^{2k})\)

\(我们发现2式只有系数不同,所以可以在k\in[0,\frac{n}{2}-1]时顺便把k\in[\frac{n}{2},n-1]计算出来,就可以实现以下时间\)

\[ T(n)=\left\{ \begin{array}{rcl} 2T(\frac{n}{2})+n&& {1

\(时间复杂度为O(nlog_2n)\)


细节

  1. 为使序列长度为\(2^m\),把不足位补0

  2. 把下标奇偶分类后的位置其实就是2进制下的反转,所以可以通过迭代(非递归)实现,实际效率也是递归版的\(1.5\)~\(2\)

\(\mathfrak{Talk\ is\ cheap,show\ you\ the\ code.}\)

#include
#include
#include
#include
using namespace std;
# define read read1()
# define Type template
Type inline T read1(){
    T n=0;
    char k;
    bool fl=0;
    do (k=getchar())=='-'&&(fl=1);while('9'a;
    public:
        Array(){}
        void push(int n){a.push_back(n);}
        Array(int* l,int* r){while(l!=r)push(*l),++l;}
        int size(){return a.size();}
        int& operator [] (const int x){return a[x];}
};
void FFT(const int len,vector&a,const int Ty,int *r=NULL){
    if(!r){
        r=new int[len];
        r[0]=0;int L=log2(len);
        f(i,0,len-1){
            r[i]=(r[i>>1]>>1)|((i&1)<_x(limit+1),_y(limit+1);
    Array ans;
    f(i,0,n)_x[i]=complex(x[i],0);
    f(i,0,m)_y[i]=complex(y[i],0);
    FFT(limit,_x,1);
    FFT(limit,_y,1);
    f(i,0,limit)_x[i]*=_y[i];
    FFT(limit,_x,-1);
    f(i,0,n+m)ans.push((int)(_x[i].x/limit+0.5));
    return ans;
}
void into(int n,Array &x){
    f(i,0,n)x.push(read);
}
Array x,y,ans;
int main(){
    int n=read,m=read;
    into(n,x),into(m,y);
    ans=x*y;
    f(i,0,n+m)printf("%d ",ans[i]);
    return 0;
}

你可能感兴趣的:(FFT(快速傅里叶变换))