全网第二好懂的FFT(快速傅里叶变换)

声明:本FFT是针对OI的。专业人员请出门左拐。

前言

很久以前,我打算学习FFT。

然而,算法导论讲的很详细,却看不懂。网上博客更别说了,什么频率之类的都来了。我暗自下了决心:写一篇人看得懂的FFT

今天讲了FFT,我对这精(xuan)妙(xue)的算法有了初步的认识。我想,我如愿以偿了。

由于此算法不好理解的主要原因是涉及大量数学知识,所以我会尽量讲的浅显一点,以会写代码为目的。部分高超的证明会略去。

算法简介

快速傅里叶变换,FFT(Fast-Fast TLE,Fast Fourier Transform),是一种高效的多项式系数点值互换的算法(不懂没关系,一会儿要讲)。最广泛的应用是计算多项式乘法。

通常,暴力展开复杂度为O($n^{2}$)。而FFT则可以达到O(nlogn)

辣么我们开始吧。

前置知识(顺便简单提一下流程,后面流程详细讲)

1.多项式

 回忆一下初中多项式的定义:

由若干个单项式相加组成的代数式叫做多项式。

单项式又是啥?

由数或字母的积组成的代数式叫做单项式。

low爆了!

我们已经是高中生了什么时候的事我怎么不知道,我们换一种定义:

 多项式   :=   f(x)=$\sum_{i=0}^{n-1}a_{i}x^{i}\qquad$

其中n称为次数。

怎么样?有没有莫比乌斯反演的既视感?

2.多项式的表示方法

上面提到的叫做系数表达式。其实多项式还有一种表示:点值表达式。

标准定义找不到啊qwq

那这么说吧:

先把多项式看做一个函数,画出它的图像

然后在上面任取n个不同的点

那么这三个点就可以唯一的确定这个多项式。至于为什么唯一,通过意识流很容易证明。

为什么要引入这个东西呢?因为如果把两个多项式转换为x相同的点值,就可以O(n)求出它们的乘积。太神奇啦!

辣么现在问题就成了:如何把原多项式转成点值,再把乘出来的点值转系数。

最直观的方法:把原多项式转成点值就取几个值,点值转系数可以高斯消元。

于是尴尬的事情发生了:

总复杂度O($n^{3}$)

看来还要想办法啊。

3.弧度制和任意三角函数(学过的往后跳)

初中的三角函数是针对锐角的。那其他角有没有三角函数呢?

当然啦。

这要从任意角说起。

高中我们定义角为一条射线(一般指x正半轴)逆时针旋转后(称为终边)与原来的射线形成的图形,允许有负数,即顺时针

所以,这是个角:

这也是个角,而且和上一个不同:

这还是个角,而且是负角:

这仍然是个角:

好吧。。。

以前用角都是有单位,即1°=一个周角的1/360

那能不能换一个没单位的呢?

定义弧度为这个角所对弧长与半径的比,这样角就是一个常数。

很容易知道,一个周角是2π弧度。即π弧度对应180°。(前面那个是圆周率  垃圾markdown

这样任意角三角函数就出来了:

在直角坐标系中,以O为圆心作一个半径为R的圆。角α的终边与圆的交点坐标(x,y),那么有

sinα=$\frac{x}{R}$

cosα=$\frac{y}{R}$

其他三角函数类似,但FFT用不到,就不说了

4.复数与单位根

实数貌似没什么特殊性质。那实数之外呢?

我们定义$i^{2}$=-1。任何复数(也就是目前的所有数)都可以表示成x+yi的形式(x,y均为实数)

等等!这不是没有意义吗?这是什么鬼玩意儿?

好吧,你可以不管它。就把它看成这个:

1 struct complex
2 {
3     double x,y;
4 };

就好了。

当然它的乘法就是把它拆开,$i^{2}$换成-1,i保留就好了。(不懂没关系,后面看代码)

由于是两个实数,所以我们可以yy出一个平面:x代表实部,y代表虚部。这上面的点都是与复数一一对应的。

单位根就是满足$w^{n}$=1的所有复数,共n个,记为$w_{n}$(注:这里的w应该是个希腊字母,但为了偷懒就用w代替)

根据意识流在复平面上,这n个点与原点连线长度相同,且平分圆周。

并且,它们是$w_{n}$,$w_{n}^{2}$,$w_{n}^{3}$......$w_{n}^{n}$的关系,我们就这么表示好了

你可以用上面的性质把n个单位根算出来

即$w_{n}^{k}$=cos$\frac{2πk}{n}$+sin$\frac{2πk}{n}$i

 Ⅳ算法流程

我们假装n是2的k次幂 即$n=2^{k}$,k为非负整数

令x=$w_{n}^{k}$,代入多项式

(注:1.如果你不想看,并且你可以在不理解的情况下背代码,可以跳过以下推导  2.以下的i都是循环变量而不是虚数单位)

$F(w_{n}^{k})=\sum_{i=0}^{n-1}a_{i}w_{n}^{ik}$

闲着没事,把它按奇偶分类:

$F(w_{n}^{k})=\sum_{i=0}^{\frac{n}{2}-1}a_{2i}w_{n}^{2ik}+a_{2i+1}w_{n}^{(2i+1)k}$

看后面那坨不顺眼

$F(w_{n}^{k})=\sum_{i=0}^{\frac{n}{2}-1}a_{2i}w_{n}^{2ik}+w_{n}^{k}a_{2i+1}w_{n}^{2ik}$

根据折半引理:

$(w_{n}^{k})^{2}=w_{\frac{n}{2}}^{k}$

可得:

$F(w_{n}^{k})=\sum_{i=0}^{\frac{n}{2}-1}a_{2i}w_{\frac{n}{2}}^{ik}+w_{n}^{k}a_{2i+1}w_{\frac{n}{2}}^{ik}$

有没有一种似曾相识的感觉呢?

所以可以递归下去:(type干啥的马上就知道了)

const double PI=acos(-1.0);
struct complex
{
    double x,y;
    complex(double x=0,double y=0):x(x),y(y){}
}a[MAXN],b[MAXN];
complex operator +(const complex& a,const complex& b){return complex(a.x+b.x,a.y+b.y);}
complex operator -(const complex& a,const complex& b){return complex(a.x-b.x,a.y-b.y);}
complex operator *(const complex& a,const complex& b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
void fft(int lim,complex *a,int type)
{
    if (lim==1)
        return;
    complex a1[lim>>1],a2[lim>>1];
    for (int i=0;i<=lim;i+=2)
        a1[i>>1]=a[i],a2[i>>1]=a[i+1];
    fft(lim>>1,a1,type);
    fft(lim>>1,a2,type);
    complex wn(cos(2.0*PI/lim),type*sin(2.0*PI/lim)),w(1,0);
    for (int i=0;i<(lim>>1);i++,w=w*wn)
    {
        a[i]=a1[i]+w*a2[i];
        a[i+(lim>>1)]=a1[i]-w*a2[i];
    }
}

于是 就完了?

怎么可能?

上面只是系数转点值。而平时点值很少用,即使用也不会是复数啊……

所以还要把点值转系数。我们称为傅里叶逆变换。

又是推式子的时间啦!

(其实这里我也不怎么懂……但结论很简单,直接记就行)

我们设$c_{i}$为多项式在$w_{n}^{-i}$的点值表达式(也就是y值),其中$0<=i<n$LaTeX可以美化呢

  $c_{k}=\sum_{i=0}^{n-1}y_{i}(w_{n}^{-k})^{i}$

把$y_{i}$拆开

  $=\sum_{i=0}^{n-1}(\sum_{j=0}^{n-1}a_{j}(w_{n}^{i})^{j})(w_{n}^{-k})^{i})$

你到前面来

  $=\sum_{i=0}^{n-1}(\sum_{j=0}^{n-1}a_{j}(w_{n}^{j})^{i})(w_{n}^{-k})^{i})$

辣眼睛的小括号

  $=\sum_{i=0}^{n-1}\sum_{j=0}^{n-1}a_{j}(w_{n}^{j})^{i}(w_{n}^{-k})^{i}$

咦?

  $=\sum_{i=0}^{n-1}\sum_{j=0}^{n-1}a_{j}(w_{n}^{j-k})^{i}$

瞎搞一波

  $=\sum_{i=0}^{n-1}a_{j}(\sum_{j=0}^{n-1}(w_{n}^{j-k})^{i})$

设$S(x)=\sum_{i=0}^{n-1}x$

 代入

$S(w_{n}^{k})=1+(w_{n}^{k})+(w_{n}^{k})^{2}+... ... +(w_{n}^{k})^{n-1}$

 当k不为0时,运用你丰富的等比数列知识

$S(w_{n}^{k})=\frac{(w_{n}^{k})^{n}-1}{(w_{n}^{k})-1}$

$S(w_{n}^{k})=0$

 k=0时,显然$S(w_{n}^{k})=n$

 手贱点了发布。。。正在赶,有缘看到可以等一下

猜你喜欢

转载自www.cnblogs.com/lstoi/p/9379501.html