概述
FTT: 快速傅里叶变换。看起来挺难的,实际上确实挺难的。
用途
求
也就是上面两个多项式相乘等于下面这个
朴素算法一个个乘 $O(n^2)$ 复杂度,FFT能在 $O(nlog(n)$ 的复杂度内解决。
点值
这个是多项式 系数表达
下面这个是 点值表示法
不难看出能用下面这个n+1
个不同的点值推出 系数表达式
FFT步骤
- 加倍次数界求值 将转
A B
系数表达式,找出2n+1
个点值,(只需要n+1
个点值就能推出一个最高次项为n
的表达式,但是,A B
相乘后有2n
,所以要找出2n+1
个值) - 逐点相乘 将两个点值相乘获得
C
的点值 - 插值 再用逆变换将
C
的点值转换成 系数表达式
第一步叫离散傅里叶变换 (DFT)
正式讲解
不难看出,如果直接用朴素算法,去求多项式乘积,第一步复杂度 $O(n^2)$,第二步$O(n)$,第三步$O(n^2)$
FFT 作用就是优化第一步和第三步,都变成$O(nlog(n))$的复杂度。
在这之前需要知道一个东西叫单位复根
单位复根
不具体讲了,讲了你也理解不了。 (其实我没理解)
想要具体了解见黑书算法导论P532,我只做简介
n次单位复根,$w^n=1$,这个数有恰好n
个,具体是啥不重要,我说个简单的理解。
复数大家都知道吧。
假设有两个复数
$z1=a+bi$
$z2=c+di$
把他们两个乘一下
求一下$z1 z2$他们的长度和角,
先求长度
是不是就等于$[z1] * [z2]$
然后你代一个数放z1 z2里面
看到这应该懂了,复数的乘法性质。
可能你还不知道这意味着啥,但是马上你就懂了
假设一个复数,长度为1,角度为,$w_n^1=cos(\frac{2\pi}{n})+sin(\frac{2\pi}n{})i$
把他画成成圆就是
那么 就相当于在圆上转了一下
如下图
看到这,后面理解性质就贼简单,你全部想象成在圆上面旋转。但是这些都不重要接下来给你退公式了,假设 A
有最高次项为 n-1
可以发现前面一堆和后面一堆很像
然后设这$A0 A1$
这个地方注意,A0,A1 里面的次项是开根号
所以是
假设你代入的是一个普通的数,假设是 ,$A(X)=A0(X^2)+xA1(X^2)$ 你还需要求 ,一共是2n
个,两边同时求还是$O(n)$.
当你带入复数 ,你可以发现一个神奇的事,要求的数量变少了
上述公式化简用上了一个公式
这个事很显然的事,在单位圆里面,改变这个比例,角度不变
你需要求的数就变成了看上去没有减少,实际上你可以发现,其中有一半其实是重复的,这又要立用到一个公式
$w_n^k=w_n^{k+n}$ 很显然,圆转了一圈,我又回来啦
所以就变成了求
举个栗子 解释一下
假设 一个 A
长度为4
最高次项就是 3
求 4 个 点值
一开始要求的有 4 个点值
通过前面那个转换, 看不懂为啥有个1的 ,注意 $w_n^0=1$
要求的点值就变成了$\{A0(1),A0(w_2^1),A1(1),A1(w_2^1)\}$ 同样是4个, 但是递归下去找每次分成两部分,就相当于折半了,(还是没有理解等会画个图给你看下)
另外还没完,上述还有一个特点: 前面一半和后面一半 很像,没错,还可以优化。这个地方又要用到一个性质.
$w_n^{k+\frac{n}{2}}=-w_n^{k}$ 很显然,你在圆里面转了半圈,不就是个相反的了么。。。。
感觉我的证明都是显然证明法,不用在意这些细节
由此可以再优化
当$k<\frac{n}{2}$
当$k>\frac{n}{2}$
网上很多写的是,其实是一个意思,哪个好理解你看哪个吧。
例子对应上面举得那个具体的例子,你就可以再次优化了。
这个地方看不懂推荐一篇神级大佬的博客 从多项式乘法到快速傅里叶变换
最后再画个图助解一下:
至此算法核心原理全部解释完毕。逆运算从点值 转换成系数表达式 ,你把矩阵写出来,就相当于乘了一个逆矩阵。就相当于再求一次DFT ,只不过 $w_n^k$ 变成他的逆,,加个负号就行了。
代码网上一大堆我这里贴个我的,测试题目
51Nod 大数乘法2
1 |
|
你以为大结局了吗?没有
优化
除了前面那个直接再表达式上的优化,,下面还有代码上的优化。
递归太慢了,可以换成迭代。另外,这空间变成了nlog(n) ,那个辅助数组优化掉也可以不好.
已经理解核心了,后面这个就不用我说了吧。。。。。。是我懒得写了,我18岁我好累
直接贴一个大哥的板子把,找的太多了都不知道是谁的了
1 | //fft |
如有错误,望指出。