FFT详解

前言

http://www.cnblogs.com/stxy-ferryman/p/8507434.html
课上zrf 大佬讲FFT,讲了一半,本蒟蒻莫名奇妙突然开始开始思考人生,回过神来发现自己早已掉(G)线(G),感谢xhkxhk帮我恶补一发。看了xhk同学的博客,经其讲解才搞懂,下面我用我自己的想法仔细写写对FFT的理解,如有错误,欢迎指正。


整体思路是以算导为基础的,so~~~

PART1:多项式

多项式这个东西,算法导论上是这么写的

A(x)=j=0n1ajxj A ( x ) = ∑ j = 0 n − 1 a j x j
乍看一眼,什么玩意,看不懂,感觉十分高大上的样子,但未免长得太丑了点,实际上这当然是在吓唬你的。那么我们把它展开来
f(x)=a0+a1x+a2x2+...+an1xn1 f ( x ) = a 0 + a 1 x + a 2 x 2 + . . . + a n − 1 x n − 1
这样看起来就和蔼多了,不就是个高次项函数嘛。
然而这只是第一个定义,要求两个它的值复杂度显然是 Θ(n2) Θ ( n 2 ) 的,那该咋整呢??于是我们来合并一下同类项,变形为这个:
f(x)=a0+(a1+(a2+...)x)x f ( x ) = a 0 + ( a 1 + ( a 2 + . . . ) x ) x

这样就可以在 Θ(n) Θ ( n ) 的复杂度之内搞定了(从里到外逐项展开,每算一项乘以个 x x ,把两重循环放在一起算)。
这个就叫做霍纳法则,名字也是个吓唬人的东西(和那个勾股定理一样,可以有不同的说法,比如:L2范数或欧几里得范数什么的)
虽说这玩意挺高大上,但遇到多项式乘法要表示乘积的系数就麻烦了。


PART2:卷积

卷积!吓人吧!吓死你!网络上讲的糊里糊涂的,我用两种不同的方式来讲清楚它。

  • 法一:线性代数

    • a=a1a2a3anb=b1b2b3bm 设 向 量 a = [ a 1 a 2 a 3 ⋮ a n ] 向 量 b = [ b 1 b 2 b 3 ⋮ b m ]
      ab=a1b1a2b1a3b1anb1a1b2a2b2a3b2anb2a1b3a2b3a3b3anb3a1bna2bna3bnanbn a · b ┬ = [ a 1 b 1 a 1 b 2 a 1 b 3 ⋯ a 1 b n a 2 b 1 a 2 b 2 a 2 b 3 ⋯ a 2 b n a 3 b 1 a 3 b 2 a 3 b 3 ⋯ a 3 b n ⋮ ⋮ ⋮ ⋱ ⋮ a n b 1 a n b 2 a n b 3 ⋯ a n b n ]
      然后,我们把斜对角的数值分别加起来,按顺序排列便得到了卷积序列,按顺序分别乘上 x x 对应的幂即可。这里写图片描述
  • 法二:列竖式

    • 这种方法较前一种就好理解多了,而且十分直观。我们拿两个式子
      A(x)=2x3+4x2+1
      B(x)=x3+5x+2 B ( x ) = x 3 + 5 x + 2
      那么
      2x52x5++4x54x5++10x40x410x4+++2x3x34x320x3x325x3+++++4x20x28x20x28x2+++++0x5x0x5x5x++++1222 2 x 3 + 4 x 2 + 0 x + 1 ∗ x 3 + 0 x 2 + 5 x + 2 4 x 3 + 8 x 2 + 0 x + 2 10 x 4 + 20 x 3 + 0 x 2 + 5 x 2 x 5 + 4 x 5 + 0 x 4 + x 3 2 x 5 + 4 x 5 + 10 x 4 + 25 x 3 + 8 x 2 + 5 x + 2

      所以我们要求的
      C(x)=A(x)B(x)=2x5+4x5+10x4+25x3+8x2+5x+2 C ( x ) = A ( x ) · B ( x ) = 2 x 5 + 4 x 5 + 10 x 4 + 25 x 3 + 8 x 2 + 5 x + 2

      这种算法显然复杂度是 Θ(n2) Θ ( n 2 ) 的,要是数据 n,m10000 n , m ≤ 10000 ,就GG了,于是我们就有了part3。

PART3:点值表示

点值表示,这里需要注意!!!
我们发现直接乘要用 Θ(n2) Θ ( n 2 ) 的时间,不够优越,点值表示就是一个把 Θ(n2) Θ ( n 2 ) 的复杂度降至 Θ(n) Θ ( n ) 的一种方法。
首先,我们需要先糊出这么一个有意思的结论:一个多项式 A(x) A ( x ) 与一个集合 {(x0,A(x0)),(x1,A(x1)),(x2,A(x2)),...,(xn1,A(xn1))} { ( x 0 , A ( x 0 ) ) , ( x 1 , A ( x 1 ) ) , ( x 2 , A ( x 2 ) ) , . . . , ( x n − 1 , A ( x n − 1 ) ) } 可以构成一个严格的一一映射。点值表示就是将 n1 n − 1 次多项式 A(x) A ( x ) 表示成该多项式所表示的函数上的 n n 个不重合的点的表示法。
便0,1,2,...,n1x0,x1,x2,...,xn1
9982443531e9+7 ( 当 然 你 想 用 998244353 或 是 1 e 9 + 7 也 没 人 拦 你 ) 。
A(x)=x2+1{(0,1),(1,2),(2,5)} 例 如 : A ( x ) = x 2 + 1 就 能 表 示 成 集 合 { ( 0 , 1 ) , ( 1 , 2 ) , ( 2 , 5 ) } 的 形 式 。
那么如何证明呢???似乎有点难抓头绪,但我们还是得试试。
不过,在这之前我要先引入一个新的概念,叫范德蒙德矩阵(这种高大上的名字都是吓唬人用的,不用管它叫什么<就像化学里的盖斯定律和物理中的动能定理一样显然>)

D=1111x0x1x2xn1x20x21x22x2n1x30x31x32x3n1xn10xn11xn12xn1n1 D = [ 1 x 0 x 0 2 x 0 3 ⋯ x 0 n − 1 1 x 1 x 1 2 x 1 3 ⋯ x 1 n − 1 1 x 2 x 2 2 x 2 3 ⋯ x 2 n − 1 ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ 1 x n − 1 x n − 1 2 x n − 1 3 ⋯ x n − 1 n − 1 ]
记作 V(x0,x1,x2,...,xn1) V ( x 0 , x 1 , x 2 , . . . , x n − 1 ) 这家伙有个神奇的性质,就是行列式
det(V(x0,x1,x2,...,xn1))=0j<kn1(xkxj) d e t ( V ( x 0 , x 1 , x 2 , . . . , x n − 1 ) ) = ∏ 0 ≤ j < k ≤ n − 1 ( x k − x j )
感觉十分有(wu)趣(liao)对不对,那让我们把它证明一下。
证法:数学归纳法

知 识 铺 垫 : 行 列 式 性 质
1.A0,det(A)=0 1. 如 果 矩 阵 A 中 某 行 或 某 列 为 0 , 则 d e t ( A ) = 0
2.Aλ,det(A)λ 2. 当 将 矩 阵 A 中 某 行 或 某 列 每 个 元 素 乘 以 λ 后 , d e t ( A ) 相 应 乘 以 λ
3.A()(),det(A) 3. 当 将 矩 阵 A 中 某 行 ( 列 ) 每 个 元 素 加 到 另 一 行 ( 列 ) 上 , d e t ( A ) 不 变
4.det(A)=det(A) 4. d e t ( A ) = d e t ( A ┬ )
5.A 5. 交 换 A 的 任 意 两 行 或 两 列 , 行 列 式 改 变 正 负 号
6.det(AB)=det(A)det(B) 6. d e t ( A B ) = d e t ( A ) d e t ( B )

有了前置知识,我们就可以开始证明啦!

第一步

D2=[11x0x1],det(D2)=x0x1() D 2 = [ 1 x 0 1 x 1 ] , d e t ( D 2 ) = x 0 − x 1 ( 成 立 )

第二步

det(Dn1)=1111x0x1x2xn2x20x21x22x2n2xn20xn21xn22xn2n2=0j<kn2(xkxj) 假 设 d e t ( D n − 1 ) = | 1 x 0 x 0 2 ⋯ x 0 n − 2 1 x 1 x 1 2 ⋯ x 1 n − 2 1 x 2 x 2 2 ⋯ x 2 n − 2 ⋮ ⋮ ⋮ ⋱ ⋮ 1 x n − 2 x n − 2 2 ⋯ x n − 2 n − 2 | = ∏ 0 ≤ j < k ≤ n − 2 ( x k − x j )

det(Dn)=1111x0x1x2xn1x20x21x22x2n1xn10xn11xn12xn1n1 那 么 所 求 即 为 d e t ( D n ) = | 1 x 0 x 0 2 ⋯ x 0 n − 1 1 x 1 x 1 2 ⋯ x 1 n − 1 1 x 2 x 2 2 ⋯ x 2 n − 1 ⋮ ⋮ ⋮ ⋱ ⋮ 1 x n − 1 x n − 1 2 ⋯ x n − 1 n − 1 | 的 值
然后我们对其进行一系列变换
41x0x20xn101x1x21xn111x2x22xn121xn1x2n1xn1n1 由 知 识 点 4 可 知 , 我 们 可 以 把 矩 阵 进 行 转 置 , 变 成 求 | 1 1 1 ⋯ 1 x 0 x 1 x 2 ⋯ x n − 1 x 0 2 x 1 2 x 2 2 ⋯ x n − 1 2 ⋮ ⋮ ⋮ ⋱ ⋮ x 0 n − 1 x 1 n − 1 x 2 n − 1 ⋯ x n − 1 n − 1 | 的 值

很妙。但接着这一步要看仔细了!!!我们把第2至n行中,第i行减去x_0倍的第i-1行。注意:从下往上处理:
1x0x20xn20xn101x1x21xn21xn111x2x22xn22xn121xn1x2n1xn2n1xn1n1 | 1 1 1 ⋯ 1 x 0 x 1 x 2 ⋯ x n − 1 x 0 2 x 1 2 x 2 2 ⋯ x n − 1 2 ⋮ ⋮ ⋮ ⋱ ⋮ x 0 n − 2 x 1 n − 2 x 2 n − 2 ⋯ x n − 1 n − 2 x 0 n − 1 x 1 n − 1 x 2 n − 1 ⋯ x n − 1 n − 1 |
=1x0x20xn20xn10xn20x01x1x21xn21xn11xn21x01x2x22xn22xn12xn22x01xn1x2n1xn2n1xn1n1xn2n1x0 = | 1 1 1 ⋯ 1 x 0 x 1 x 2 ⋯ x n − 1 x 0 2 x 1 2 x 2 2 ⋯ x n − 1 2 ⋮ ⋮ ⋮ ⋱ ⋮ x 0 n − 2 x 1 n − 2 x 2 n − 2 ⋯ x n − 1 n − 2 x 0 n − 1 − x 0 n − 2 · x 0 x 1 n − 1 − x 1 n − 2 · x 0 x 2 n − 1 − x 2 n − 2 · x 0 ⋯ x n − 1 n − 1 − x n − 1 n − 2 · x 0 |
=1x01x0x20x0x0xn20xn30x0xn10xn20x01x11x0x21x1x0xn21xn31x0xn11xn21x01x21x0x22x2x0xn22xn32x0xn12xn22x01xn11x0x2n1xn1x0xn2n1xn3n1x0xn1n1xn2n1x0 = | 1 1 1 ⋯ 1 x 0 − 1 · x 0 x 1 − 1 · x 0 x 2 − 1 · x 0 ⋯ x n − 1 − 1 · x 0 x 0 2 − x 0 · x 0 x 1 2 − x 1 · x 0 x 2 2 − x 2 · x 0 ⋯ x n − 1 2 − x n − 1 · x 0 ⋮ ⋮ ⋮ ⋱ ⋮ x 0 n − 2 − x 0 n − 3 · x 0 x 1 n − 2 − x 1 n − 3 · x 0 x 2 n − 2 − x 2 n − 3 · x 0 ⋯ x n − 1 n − 2 − x n − 1 n − 3 · x 0 x 0 n − 1 − x 0 n − 2 · x 0 x 1 n − 1 − x 1 n − 2 · x 0 x 2 n − 1 − x 2 n − 2 · x 0 ⋯ x n − 1 n − 1 − x n − 1 n − 2 · x 0 |
=1000011(x1x0)x1(x1x0)xn31(x1x0)xn21(x1x0)11(x2x0)x2(x2x0)xn32(x2x0)xn22(x2x0)11(xn1x0)xn1(xn1x0)xn3n1(xn1x0)xn2n1(xn1x0) = | 1 1 1 ⋯ 1 0 1 · ( x 1 − x 0 ) 1 · ( x 2 − x 0 ) ⋯ 1 · ( x n − 1 − x 0 ) 0 x 1 · ( x 1 − x 0 ) x 2 · ( x 2 − x 0 ) ⋯ x n − 1 · ( x n − 1 − x 0 ) ⋮ ⋮ ⋮ ⋱ ⋮ 0 x 1 n − 3 · ( x 1 − x 0 ) x 2 n − 3 · ( x 2 − x 0 ) ⋯ x n − 1 n − 3 · ( x n − 1 − x 0 ) 0 x 1 n − 2 · ( x 1 − x 0 ) x 2 n − 2 · ( x 2 − x 0 ) ⋯ x n − 1 n − 2 · ( x n − 1 − x 0 ) |

好累啊,但是我们继续。将此多项式展开,你会发现:由于第一列除了第一项是1以外,其它全都是0,所以展开之后只留 D(1,1) D ( 1 , 1 ) 及其代数余子式,别的都化成0了。于是乎我们展开可以得到这么个东西:
1(x1x0)x1(x1x0)xn31(x1x0)xn21(x1x0)1(x2x0)x2(x2x0)xn32(x2x0)xn22(x2x0)1(xn1x0)xn1(xn1x0)xn3n1(xn1x0)xn2n1(xn1x0) | 1 · ( x 1 − x 0 ) 1 · ( x 2 − x 0 ) ⋯ 1 · ( x n − 1 − x 0 ) x 1 · ( x 1 − x 0 ) x 2 · ( x 2 − x 0 ) ⋯ x n − 1 · ( x n − 1 − x 0 ) ⋮ ⋮ ⋱ ⋮ x 1 n − 3 · ( x 1 − x 0 ) x 2 n − 3 · ( x 2 − x 0 ) ⋯ x n − 1 n − 3 · ( x n − 1 − x 0 ) x 1 n − 2 · ( x 1 − x 0 ) x 2 n − 2 · ( x 2 − x 0 ) ⋯ x n − 1 n − 2 · ( x n − 1 − x 0 ) |

好看多了吧!接着,我们再用知识点2,可以将每一列的公因数都提出来,我们就得到了这个:
(x1x0)(x2x0)(xn1x0)1x1x21xn211x2x22xn221x3x23xn231xn1x2n1xn2n1 ( x 1 − x 0 ) ( x 2 − x 0 ) ⋯ ( x n − 1 − x 0 ) | 1 1 1 ⋯ 1 x 1 x 2 x 3 ⋯ x n − 1 x 1 2 x 2 2 x 3 2 ⋯ x n − 1 2 ⋮ ⋮ ⋮ ⋱ ⋮ x 1 n − 2 x 2 n − 2 x 3 n − 2 ⋯ x n − 1 n − 2 |

4(233() 再 用 知 识 点 4 ( 我 似 乎 发 现 前 面 根 本 不 需 要 转 置 这 一 步 233 , 但 是 我 懒 得 改 了 , 假 装 我 不 知 道 ( 逃 )
=(x1x0)(x2x0)(xn1x0)1111x1x2x3xn1x21x22x23x2n1xn21xn22xn23xn2n1 = ( x 1 − x 0 ) ( x 2 − x 0 ) ⋯ ( x n − 1 − x 0 ) | 1 x 1 x 1 2 ⋯ x 1 n − 2 1 x 2 x 2 2 ⋯ x 2 n − 2 1 x 3 x 3 2 ⋯ x 3 n − 2 ⋮ ⋮ ⋮ ⋱ ⋮ 1 x n − 1 x n − 1 2 ⋯ x n − 1 n − 2 |
=(x1x0)(x2x0)(xn1x0)1j<kn1(xkxj) = ( x 1 − x 0 ) ( x 2 − x 0 ) ⋯ ( x n − 1 − x 0 ) ∏ 1 ≤ j < k ≤ n − 1 ( x k − x j )
=0j<kn1(xkxj) = ∏ 0 ≤ j < k ≤ n − 1 ( x k − x j )

呼~~~~终于证完了!!!!!
那么下一步我们就继续讲插值(把点值表达改为多项式)吧。

等等,让我们再来看一个东西:拉格朗日公式

A(x)=k=0n1ykjk(xxj)jk(xkxj) A ( x ) = ∑ k = 0 n − 1 y k · ∏ j ≠ k ( x − x j ) ∏ j ≠ k ( x k − x j )
评价:这种算法十分 (che)(dan) 优 ( c h e ) 越 ( d a n ) 。我越看越想证明,那就证呗。你会发现:证到一半,我们前面要的东西也就证完了。
这个公式证明有两步

一:存在的唯一性确认

其实这步证好,我们要求的东西也就搞定了。
这时我们应该先把别的杂念全部抛开,不要和上面的东西混淆了,否则越看越糊涂
好,我们准备开始。
f(x),f(xj)=yj(j=0,1,,n) 先 设 一 个 函 数 f ( x ) , f ( x j ) = y j ( j = 0 , 1 , ⋯ , n ) 再 设 一 个 多 项 式

Ln(x)=a0+a1(xx0)+a2(xx0)(xx1)++an(xx0)(xx1)(xxn1) L n ( x ) = a 0 + a 1 ( x − x 0 ) + a 2 ( x − x 0 ) ( x − x 1 ) + ⋯ + a n ( x − x 0 ) ( x − x 1 ) ⋯ ( x − x n − 1 )
满足
Ln(xk)=yk(k=0,1,,n) L n ( x k ) = y k ( k = 0 , 1 , ⋯ , n )
然后,我们把 x0,x1,,xn x 0 , x 1 , ⋯ , x n 带入,得:
a0+a1(x0x0)+a0+a1(x1x0)+a0+a1(xnx0)++an(x0x0)(x0x1)(x0xn1)+an(x1x0)(x1x1)(x1xn1)+an(xnx0)(xnx1)(xnxn1)=y0=y1=yn { a 0 + a 1 ( x 0 − x 0 ) + ⋯ + a n ( x 0 − x 0 ) ( x 0 − x 1 ) ⋯ ( x 0 − x n − 1 ) = y 0 a 0 + a 1 ( x 1 − x 0 ) + ⋯ + a n ( x 1 − x 0 ) ( x 1 − x 1 ) ⋯ ( x 1 − x n − 1 ) = y 1 ⋮ a 0 + a 1 ( x n − x 0 ) + ⋯ + a n ( x n − x 0 ) ( x n − x 1 ) ⋯ ( x n − x n − 1 ) = y n
我们发现这组方程有好几项是可以消掉的,于是乎,我们就得到如下的形式:
a0a0+a1(x1x0)a0+a1(xnx0)++an(xnx0)(xnx1)(xnxn1)=y0=y1=yn { a 0 = y 0 a 0 + a 1 ( x 1 − x 0 ) = y 1 ⋮ a 0 + a 1 ( x n − x 0 ) + ⋯ + a n ( x n − x 0 ) ( x n − x 1 ) ⋯ ( x n − x n − 1 ) = y n
接着,我们就可以写出以 a0,a1,,an a 0 , a 1 , ⋯ , a n 为系数的每一项的行列式
1110(x1x0)(xnx0)00(xnx0)(xnx1)00(xnx0)(xnx1)(xnxn1) | 1 0 0 ⋯ 0 1 ( x 1 − x 0 ) 0 ⋯ 0 ⋮ ⋮ ⋮ ⋱ ⋮ 1 ( x n − x 0 ) ( x n − x 0 ) ( x n − x 1 ) ⋯ ( x n − x 0 ) ( x n − x 1 ) ⋯ ( x n − x n − 1 ) |
=[(x1x0)][(x2x0)(x2x1)[[(xnx0)(xnx1)(xnxn1)] = [ ( x 1 − x 0 ) ] [ ( x 2 − x 0 ) ( x 2 − x 1 ) [ ⋯ [ ( x n − x 0 ) ( x n − x 1 ) ⋯ ( x n − x n − 1 ) ]

仔细观察该式,我们可以发现,该式相当于两两不同的 xi x i xj x j 的差的乘积
由于当 ij i ≠ j xixj x i ≠ x j 所以该式的值不为0。
然后我们需要一个结论:若n*n的矩阵是奇异的(无逆矩阵的),当且仅当该矩阵的行列式值为零
然后

未完待续。。。。

忽略下面。。。

方法:线性代数
又是线性代数( 线 搞 得 好 像 拉 格 朗 日 插 值 法 不 是 线 性 代 数 似 的 ),不过这线性代数可比拉格朗日公式通俗易懂多了(那必须的)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值