算法学习FFT系列(1):初习快速傅里叶变换
引入
这个坑已经在我脑海里占了很久了,但是一直没有水平写,今天尝试着写写看FFT的算法学习。
FFT在OI中最大的作用是加速卷积。理论上背板子是没毛病的,但是仍然遇到了一些考定义的毒瘤题,所以还是理解比较好。
多项式乘法
定义
多项式 A(x)=∑inai∗xi,B(x)=∑inbi∗xi A ( x ) = ∑ i n a i ∗ x i , B ( x ) = ∑ i n b i ∗ x i
多项式乘法就是
C(x)=∑i2n−1(∑jiaj∗bi−j)xi C ( x ) = ∑ i 2 n − 1 ( ∑ j i a j ∗ b i − j ) x i
显然,多项式乘法需要 O(n2) O ( n 2 ) 的复杂度。
表示方法
普通的多项式表示方法把n阶多项式 A(x) A ( x ) 表示为向量 A A
这里需要引入一种全新的表示方法——点值表示法。
也就是
表示为 A(A(x0),A(x1),A(x2)⋯A(xn)) A ( A ( x 0 ) , A ( x 1 ) , A ( x 2 ) ⋯ A ( x n ) )
n阶多项式和n个互不相同的点值表示一一对应。
这样的表示方法的优点是什么?考虑多项式乘法的过程。
C(x)=∑i2n−1(∑jiaj∗bi−j)xi C ( x ) = ∑ i 2 n − 1 ( ∑ j i a j ∗ b i − j ) x i
=∑i2n−1∑ji(aj∗xj)∗(bi−j∗xi−j) = ∑ i 2 n − 1 ∑ j i ( a j ∗ x j ) ∗ ( b i − j ∗ x i − j )
=∑j2n−1(aj∗xj)∗∑i2n−1(bi∗xi) = ∑ j 2 n − 1 ( a j ∗ x j ) ∗ ∑ i 2 n − 1 ( b i ∗ x i )
转化成点值表示的两个式子,不难发现,其乘法复杂度是 O(n) O ( n ) 的
FFT的总路线:系数表达式->点值表达式->乘法->点值表达式->系数表达式
插值(*)
这个东西是顺便一提,FFT中系数表达式<->点值表达式过程并不是FFT的专属,但是确是FFT的关键。这一过程被称之为插值。证明插值的唯一性(也就是n阶多项式和n个互不相同的点值表示一一对应。)需要通过范德蒙德矩阵的可逆性。
⎡⎣⎢⎢⎢⎢11…1x0x1…xnx20x21…x2n…⋯…⋯xn0xn1…xnn⎤⎦⎥⎥⎥⎥⎡⎣⎢⎢⎢a0a1…an⎤⎦⎥⎥⎥=⎡⎣⎢⎢⎢y0y1…yn⎤⎦⎥⎥⎥ [ 1 x 0 x 0 2 … x 0 n 1