借用了一些他人的博客供自己理解。此为FFT的学习笔记。
前言
几个相关的多项式算法:
FFT:快速傅里叶变换 - O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n)) 计算多项式乘法
DFT:离散傅里叶变换 - O ( n 2 ) O(n^2) O(n2) 计算多项式乘法
FNTT/NTT : 快速傅里叶变换的优化版 - 优化常数和误差
FWT :快速沃尔什变换 - 利用类似FFT的方法解决一类卷积问题
MTT : myy的FFT - 任意模数
FMT :快速莫比乌斯变换
多项式
多项式乘法
设 P ( x ) P(x) P(x)和 Q ( x ) Q(x) Q(x)为两个关于 x x x的长度分别为 n n n、 m m m的多项式
P ( x ) = ∑ i = 0 n a i ∗ x i P(x) = \sum_{i = 0}^{n} a_i * x^i P(x)=∑i=0nai∗xi
Q ( x ) = ∑ i = 0 m b i ∗ x i Q(x) = \sum_{i = 0}^{m} b_i * x^i Q(x)=∑i=0mbi∗xi
则 P ( x ) ∗ Q ( x ) = ∑ i = 0 n ∑ j = 0 m a i x i ∗ b j x j P(x) * Q(x) = \sum_{i = 0}^{n}\sum_{j = 0}^{m}a_i x^i* b_jx^j P(x)∗Q(x)=∑i=0n∑j=0maixi∗bjxj
我们往往表达为卷积的形式:
设 P ( x ) ∗ Q ( x ) P(x) * Q(x) P(x)∗Q(x)得到的答案多项式为 C ( x ) C(x) C(x),则可写为卷积的形式:
C k = ∑ i = 0 k P i ∗ Q k − i C_k = \sum_{i = 0}^{k}P_i * Q_{k - i} Ck=∑i=0kPi∗Qk−i
表示一个多项式
系数表示法
设 A ( x ) A(x) A(x)表示一个 n + 1 n + 1 n+1阶的多项式
形如 a 0 + a 1 x 1 + a 2 x 2 + . . . + a n x n a_0 + a_1x^1 + a_2x^2 + ... + a_nx^n a0+a1x1+a2x2+...+anxn ( a i a_i ai为系数)
则 A ( x ) = ∑ i = 0 n a i ∗ x i A(x) = \sum_{i = 0}^{n} a_i * x^i A(x)=∑i=0nai∗xi
显然,这样计算两个多项式的时间复杂度为 O ( n 2 ) O(n^2) O(n2)
点值表示法
对于一个多项式 y = f ( x ) y = f(x) y=f(x),将 n n n个不同的 x x x带入多项式,会得到 n n n个不同的 y y y(这里的不同不是横向比较 y i y_i yi, 而是纵向地对于不同的多项式而言)。
那么这 n n n个不同的 x i x_i xi和 y i y_i yi组成了 n n n个点对,它们唯一确定了一个多项式的表达式
其中 y i = ∑ j = 0 n − 1 a j ∗ x i j y_i = \sum_{j = 0}^{n - 1} a_j * x_i^j yi=∑j=0n−1aj∗xij
这样计算多项式乘法的时间复杂度还是为 O ( n 2 ) O(n^2) O(n2)
选 n n n个点对的时间复杂度为 O ( n ) O(n) O(n)
每个点对的时间复杂度为 O ( n ) O(n) O(n)
可以看到,对于两种表示法,时间复杂度均为 O ( n 2 ) O(n^2) O(n2)
对于系数表示法,每个点的系数固定,不好优化
而点值表示法是可以进行优化的,请看下文。
复数
一些涉及的知识点
向量
具有大小和方向的量
在几何中通常用带有箭头的线段表示
表示为 S T ⃗ \vec {ST} ST
平行四边形定则
A D ⃗ \vec {AD} AD + A B ⃗ \vec {AB} AB = A C ⃗ \vec {AC} AC
圆的弧度制
等于半径长的圆弧所对的圆心角叫做1弧度的角,用符号 r a d rad rad表示,读作弧度。用弧度作为单位来度量角的制度叫做弧度制。
1 ∘ = π 180 r a d 1^∘ = \frac {\pi}{180} rad 1∘=180πrad
18 0 ∘ = π r a d 180^∘ = \pi rad 180∘=πrad
虚数单位
引进一个新数 i i i,称作虚数单位,规定:
(1). i 2 = − 1 i^2 = -1 i2=−1
(2). 实数可以和它进行四则运算,原有的加法、乘法运算率仍然成立。
虚数单位 i i i定义为二次方程 x 2 + 1 = = 0 x^2 + 1 == 0 x2+1==0的一个解。又可以表示为 x 2 = = − 1 x^2 == -1 x2==−1
所以虚数单位 i i i又可以表示为 i = − 1 i = \sqrt {-1} i=−1
但是,使用这种记法时需要非常谨慎,这是因为有些在实数范围内成立的公式在复数范围内并不成立。
a ∗ b = a b \sqrt a * \sqrt b = \sqrt {ab} a∗b=ab 仅对于非负实数和才成立
为了避免这种错误,尽量不要用平方根来表示虚数。例如我们不应使用 − n \sqrt {-n} −n,而应该用 n i \sqrt {ni} ni
复数
设实数 a a a, b b b。形如 a + b i a + bi a+bi的数叫做复数。复数域是目前已知最大的数域。
在复平面中, x x x轴表示实数, y y y轴(除原点)代表虚数。从 O ( 0 , 0 ) O(0, 0) O(0,0)到 ( a , b ) (a, b) (a,b)的向量表示复数 a + b i a + bi a+bi
模长 : 从 O ( 0 , 0 ) O(0,0) O(0,0)到 ( a , b ) (a, b) (a,b)的距离,即为 a 2 + b 2 \sqrt {a^2 + b^2} a2+b2
幅角 : 假设以逆时针为正方向,从 x x x轴正半轴到已知向量的转角的有向角
运算法则
加法
因为在复平面中,复数可以表示为向量。
所以复数的加法可以转换为向量加法,满足平行四边形定则。
乘法
几何定义: 复数相乘,模长相乘,幅角相加
代数定义:
( a + b i ) ∗ ( c + d i )