分治法求解多项式乘法

多项式乘法问题

多项式乘法是将两个或多个多项式相乘,得到一个新的多项式。

一个多项式通常写成如下的形式(系数表示): P ( x ) = a n x n + a n − 1 x n − 1 + … + a 1 x + a 0 P(x) = a_nx^n + a_{n-1}x^{n-1} + \ldots + a_1x + a_0 P(x)=anxn+an1xn1++a1x+a0其中 a i a_{i} ai是多项式的系数, x x x 是变量, n n n 是多项式的次数。

假设我们有两个多项式: P ( x ) = a n x n + a n − 1 x n − 1 + … + a 1 x + a 0 Q ( x ) = b m x m + b m − 1 x m − 1 + … + b 1 x + b 0 P(x) = a_nx^n + a_{n-1}x^{n-1} + \ldots + a_1x + a_0 \\ Q(x) = b_mx^m + b_{m-1}x^{m-1} + \ldots + b_1x + b_0 P(x)=anxn+an1xn1++a1x+a0Q(x)=bmxm+bm1xm1++b1x+b0它们的乘积 R ( x ) = P ( x ) ⋅ Q ( x ) R(x)=P(x)⋅Q(x) R(x)=P(x)Q(x) 可以通过将 P ( x ) P(x) P(x) 中的每一项与 Q ( x ) Q(x) Q(x) 中的每一项相乘,然后将结果合并得到: R ( x ) = ∑ i = 0 n ∑ j = 0 m a i b j x i + j R(x) = \sum_{i=0}^{n} \sum_{j=0}^{m} a_ib_jx^{i+j} R(x)=i=0nj=0maibjxi+j其中, i i i j j j 分别表示 P ( x ) P(x) P(x) Q ( x ) Q(x) Q(x) 中各项的指数, a i a_{i} ai b j b_{j} bj 分别是对应的系数。

暴力求解

对于规模相当的两个多项式相乘,对于 P ( x ) P(x) P(x) 的每个项,都要与 Q ( x ) Q(x) Q(x) 相乘,并进行结果的累加。这个过程的算法复杂度很容易得知为 O ( n 2 ) O(n^{2}) O(n2)

#include <iostream>
#include <vector>

using namespace std;

// 结构体表示多项式的一项
struct Term {
    
    
    int coefficient;
    int exponent;
};

// 函数实现多项式相乘
vector<Term> multiplyPolynomials(vector<Term>& poly1, vector<Term>& poly2) {
    
    
    vector<Term> result;

    for (int i = 0; i < poly1.size(); ++i) {
    
    
        for (int j = 0; j < poly2.size(); ++j) {
    
    
            int newCoefficient = poly1[i].coefficient * poly2[j].coefficient;
            int newExponent = poly1[i].exponent + poly2[j].exponent;

            bool termExists = false;
            for (int k = 0; k < result.size(); ++k) {
    
    
                if (result[k].exponent == newExponent) {
    
    
                    result[k].coefficient += newCoefficient;
                    termExists = true;
                    break;
                }
            }

            if (!termExists) {
    
    
                Term newTerm = {
    
    newCoefficient, newExponent};
                result.push_back(newTerm);
            }
        }
    }

    return result;
}

int main() {
    
    
    vector<Term> poly1 = {
    
    {
    
    2, 2}, {
    
    3, 1}, {
    
    1, 0}};
    vector<Term> poly2 = {
    
    {
    
    4, 1}, {
    
    1, 0}};

    vector<Term> result = multiplyPolynomials(poly1, poly2);

    cout << "Result: ";
    for (int i = 0; i < result.size(); ++i) {
    
    
        cout << result[i].coefficient << "x^" << result[i].exponent;
        if (i < result.size() - 1) {
    
    
            cout << " + ";
        }
    }
    cout << endl;

    return 0;
}


背景展开

1. 系数表示值计算复杂度

对于给定多项式和值 x x x : A ( x ) = a n − 1 x n − 1 + … + a 1 x + a 0 B ( x ) = b n − 1 x n − 1 + … + b 1 x + b 0 A(x) = a_{n-1}x^{n-1} + \ldots + a_1x + a_0 \\ \\ B(x) = b_{n-1}x^{n-1} + \ldots + b_1x + b_0 A(x)=an1xn1++a1x+a0B(x)=bn1xn1++b1x+b0- 加法计算复杂度 O ( n ) O(n) O(n)
A ( x ) + B ( x ) = ( a 0 + b 0 ) + ( a 1 + b 1 ) x + . . . ( a n − 1 + b n − 1 ) x n − 1 A(x)+B(x)=(a_{0}+b_{0})+(a_{1}+b_{1})x+...(a_{n-1}+b_{n-1})x^{n-1} A(x)+B(x)=(a0+b0)+(a1+b1)x+...(an1+bn1)xn1 - 乘法计算复杂度 采用Horner (霍氏法则) O ( n ) O(n) O(n) A ( x ) = a 0 + ( x ( a 1 + x ( a 2 + . . . + x ( a n − 2 + x ( a n − 1 ) ) . . . ) ) A(x) = a_0 + (x(a_1 + x(a_2 + ... + x(a_{n−2} + x(a_{n−1}))...)) A(x)=a0+(x(a1+x(a2+...+x(an2+x(an1))...))


2. 点值法表示多项式

在这里插入图片描述
当我们用点值法表示多项式时,我们通常是指将多项式表示为一组在特定点 x x x 处的函数值。

假设我们有一个多项式 P ( x ) P(x) P(x) ,我们可以在一些特定的点 x 1 , x 2 , … , x n x_1,x_2,…,x_n x1,x2,,xn 处计算它的值 P ( x 1 ) , P ( x 2 ) , … , P ( x n ) P(x_1),P(x_2),…,P(x_n) P(x1),P(x2),,P(xn) 。这些点和相应的函数值可以表示为: ( x 1 , P ( x 1 ) ) ( x 2 , P ( x 2 ) ) . . . . . . ( x n , P ( x n ) ) (x_1, P(x_1)) (x_2, P(x_2)) ...... (x_n, P(x_n)) (x1,P(x1))(x2,P(x2))......(xn,P(xn))一个 n n n 次的复系数单变量多项式恰好有 n n n 个复根。


3. 点值表示值计算复杂度

对于给定多项式点值列 x x x : A ( x ) : ( x 0 , y 0 ) , . . . , ( x n − 1 , y n − 1 ) B ( x ) : ( x 0 , z 0 ) , . . . , ( x n − 1 , z n − 1 ) A(x) : (x_0,y_0),...,(x_{n-1},y_{n-1}) \\ \\ B(x) : (x_0,z_0),...,(x_{n-1},z_{n-1}) A(x):(x0,y0),...,(xn1,yn1)B(x):(x0,z0),...,(xn1,zn1)- 加法计算复杂度 O ( n ) O(n) O(n)
A ( x ) + B ( x ) : ( x 0 , y 0 + z 0 ) , . . . , ( x n − 1 , y n − 1 + z n − 1 ) A(x)+B(x):(x_{0},y_{0}+z_0),...,(x_{n-1},y_{n-1}+z_{n-1}) A(x)+B(x):(x0,y0+z0),...,(xn1,yn1+zn1) - 乘法计算复杂度 O ( n ) O(n) O(n) 但是需要用 2 n 2n 2n 个点表示 A ( x ) A(x) A(x) B ( x ) B(x) B(x) A ( x ) × B ( x ) : ( x 0 , y 0 × z 0 ) , . . . , ( x 2 n − 1 , y 2 n − 1 × z 2 n − 1 ) A(x) \times B(x):(x_0,y_0 \times z_0),...,(x_{2n-1},y_{2n-1} \times z_{2n-1}) A(x)×B(x):(x0,y0×z0),...,(x2n1,y2n1×z2n1)- 计算给定点 s s s ,使用拉格朗日公式 O ( n 2 ) O(n^2) O(n2): A ( s ) = ∑ k = 0 n − 1 y k ∏ j ≠ k ( s − x j ) ∏ j ≠ k ( x k − x j ) A(s)=\sum_{k=0}^{n-1}y_k\frac{\prod _{j\ne k}(s-x_j)}{\prod _{j\ne k}(x_k-x_j)} A(s)=k=0n1ykj=k(xkxj)j=k(sxj)


4. 系数法和点值法比较

表示方法 多项式相乘 多项式算值
系数法 O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n)
点值法 O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2)

如果能够同时利用 系数法的算值点值法的相乘 的低复杂度计算。那么对于整个多项式相乘就有了一个复杂度比较低的解决方式。其中的关键就是找到两者之间的沟通桥梁


5. 系数法和点值法的转换

在这里插入图片描述

系数法 → \rightarrow 点值法(通过矩阵向量乘法或 n n n 次霍氏乘法) O ( n 2 ) O(n^2) O(n2)

给定多项式 a ( x ) = a 0 + a 1 x + … + a n − 1 x n − 1 a (x) = a_0 + a_1x +…+ a_{n-1} x_{n - 1} a(x)=a0+a1x++an1xn1,在 n n n 个不同的点处求值 x 0 , … , x n − 1 x_0,…, x_{n-1} x0,,xn1: [ y 0 y 1 y 2 ⋮ y n − 1 ] = [ 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 ] [ a 0 a 1 a 2 ⋮ a n − 1 ] \begin{bmatrix}y_0\\y_1\\y_2\\\vdots \\y_{n-1}\end{bmatrix} = \begin{bmatrix} 1& x_0& x_0^2 & \dots &x_0^{n-1} \\ 1& x_1& x_1^2 & \dots & x_1^{n-1}\\ 1& x_2& x_2^2 & \dots & x_2^{n-1}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 1& x_{n-1} & x_{n-1}^2 & \dots & x_{n-1}^{n-1} \end{bmatrix}\begin{bmatrix}a_0\\a_1\\a_2\\\vdots\\a_{n-1}\end{bmatrix} y0y1y2yn1 = 1111x0x1x2xn1x02x12x22xn12x0n1x1n1x2n1xn1n1 a0a1a2an1

点值法 → \rightarrow 系数法 (高斯消元 O ( n 3 ) O(n^3) O(n3) / 快速矩阵 O ( n 2.38 ) O(n^{2.38}) O(n2.38)):

给定n个不同的点 x 0 , … , x n − 1 x_0,…, x_{n-1} x0,,xn1和值 y 0 , … , y n − 1 y_0,…, y_{n - 1} y0,,yn1,求唯一多项式 A ( x ) = a 0 + a 1 x + … + a n − 1 x n − 1 A(x) = a_0 + a_1x +…+ a_{n-1} x_{n-1} A(x)=a0+a1x++an1xn1: [ a 0 a 1 a 2 ⋮ a n − 1 ] = [ 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 ] − 1 [ y 0 y 1 y 2 ⋮ y n − 1 ] \begin{bmatrix}a_0\\a_1\\a_2\\\vdots\\a_{n-1}\end{bmatrix} = \begin{bmatrix} 1& x_0& x_0^2 & \dots &x_0^{n-1} \\ 1& x_1& x_1^2 & \dots & x_1^{n-1}\\ 1& x_2& x_2^2 & \dots & x_2^{n-1}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 1& x_{n-1} & x_{n-1}^2 & \dots & x_{n-1}^{n-1} \end{bmatrix}^{-1}\begin{bmatrix}y_0\\y_1\\y_2\\\vdots \\y_{n-1}\end{bmatrix} a0a1a2an1 = 1111x0x1x2xn1x02x12x22xn12x0n1x1n1x2n1xn1n1 1 y0y1y2yn1 其中等式右侧有关 x i x_i xi 的矩阵为范德蒙矩阵,当 x i x_i xi 不同时可逆。

通过直接线性代数的计算,并不能在低于 O ( n 2 ) O(n^2) O(n2) 的复杂度下完成两种表示方式的相互转换,甚至会增加额外的计算代价。这是难以接受的,因此我们需要寻找一种能够高效完成两种表示方式转换的算法,并且复杂度最好能够控制在 O ( n 2 ) O(n^2) O(n2) 以内。


快速傅里叶变换 FFT

在这里插入图片描述
可以使用快速傅里叶变换(FFT)来实现系数表示和点值表示的转换。FFT 可以在 O ( n l o g ⁡ n ) O(nlog⁡n) O(nlogn) 的时间内将多项式从系数形式转换为点值形式,以及从点值形式转换回系数形式。

1. 多项式乘法的分治

给定多项式如下: A ( x ) = a 0 + a 1 x + a 2 x 2 + a 3 x 3 + a 4 x 4 + a 5 x 5 + a 6 x 6 + a 7 x 7 A(x)=a_0+a_1x+a_2x^2+a_3x^3+a_4x^4+a_5x^5+a_6x^6+a_7x^7 A(x)=a0+a1x+a2x2+a3x3+a4x4+a5x5+a6x6+a7x7可以有如下两种分治测略:

拆分成低次和高次: A l o w ( x ) = a 0 + a 1 x + a 2 x 2 + a 3 x 3 A h i g h ( x ) = a 4 + a 5 x + a 6 x 2 + a 7 x 3 A_{low}(x)=a_0+a_1x+a_2x^2+a_3x^3 \\ A_{high}(x)=a_4+a_5x+a_6x^2+a_7x^3 Alow(x)=a0+a1x+a2x2+a3x3Ahigh(x)=a4+a5x+a6x2+a7x3合并 A ( x ) = A l o w ( x ) + x 4 A h i g h ( x ) A(x)=A_{low}(x)+x^4A_{high}(x) A(x)=Alow(x)+x4Ahigh(x)

拆分成奇偶次: A e v e n ( x ) = a 0 + a 2 x + a 4 x 2 + a 6 x 3 A o d d ( x ) = a 1 + a 3 x + a 5 x 2 + a 7 x 3 A_{even}(x)=a_0+a_2x+a_4x^2+a_6x^3 \\ A_{odd}(x)=a_1+a_3x+a_5x^2+a_7x^3 Aeven(x)=a0+a2x+a4x2+a6x3Aodd(x)=a1+a3x+a5x2+a7x3合并 A ( x ) = A e v e n ( x 2 ) + x A o d d ( x 2 ) A(x)=A_{even}(x^2)+xA_{odd}(x^2) A(x)=Aeven(x2)+xAodd(x2)


2. 取值的直觉

给定多项式 A ( x ) = a 0 + a 1 x + … + a n − 1 x n − 1 A (x) = a_0 + a_1x +…+ a_{n-1} x_{n - 1} A(x)=a0+a1x++an1xn1,在 n n n 个不同的点处求值 x 0 , … , x n − 1 x_0,…, x_{n-1} x0,,xn1

关于 x i x_i xi 的取值怎么取,一般性的直觉会选 0 , ± 1 , ± 2... 0,\pm 1,\pm 2... 0,±1,±2...。这是没问题的,直觉告诉我们选择对称的不同数值可以减少计算量。下面我们来验证这一直觉是否合理:

假如使用奇偶拆分法拆分 A ( x ) = a 0 + a 1 x + a 2 x 2 + a 3 x 3 + a 4 x 4 + a 5 x 5 + a 6 x 6 + a 7 x 7 A(x)=a_0+a_1x+a_2x^2+a_3x^3+a_4x^4+a_5x^5+a_6x^6+a_7x^7 A(x)=a0+a1x+a2x2+a3x3+a4x4+a5x5+a6x6+a7x7
A e v e n ( x ) = a 0 + a 2 x + a 4 x 2 + a 6 x 3 A o d d ( x ) = a 1 + a 3 x + a 5 x 2 + a 7 x 3 A_{even}(x)=a_0+a_2x+a_4x^2+a_6x^3 \\ A_{odd}(x)=a_1+a_3x+a_5x^2+a_7x^3 Aeven(x)=a0+a2x+a4x2+a6x3Aodd(x)=a1+a3x+a5x2+a7x3 A ( x ) = A e v e n ( x 2 ) + x A o d d ( x 2 ) A ( − x ) = A e v e n ( x 2 ) − x A o d d ( x 2 ) A(x)=A_{even}(x^2)+xA_{odd}(x^2) \\ A(-x)=A_{even}(x^2)-xA_{odd}(x^2) A(x)=Aeven(x2)+xAodd(x2)A(x)=Aeven(x2)xAodd(x2)带入 ± 1 \pm 1 ±1 A ( 1 ) = A e v e n ( 1 ) + x A o d d ( 1 ) A ( − 1 ) = A e v e n ( 1 ) − A o d d ( 1 ) A(1)=A_{even}(1)+xA_{odd}(1) \\ A(-1)=A_{even}(1)-A_{odd}(1) A(1)=Aeven(1)+xAodd(1)A(1)=Aeven(1)Aodd(1)可以通过在一点处求 2 个 n − 1 2 \frac{n-1}{2} 2n1 次多项式来求 2 个点上 n − 1 n-1 n1 次多项式的值。

如果在此基础上再引入复数 i i i 那么你将会看到如下光景: A ( 1 ) = A e v e n ( 1 ) + A o d d ( 1 ) A ( − 1 ) = A e v e n ( 1 ) − A o d d ( 1 ) A ( i ) = A e v e n ( − 1 ) + i A o d d ( − 1 ) A ( − i ) = A e v e n ( − 1 ) − i A o d d ( − 1 ) A(1)=A_{even}(1)+A_{odd}(1) \\ A(-1)=A_{even}(1)-A_{odd}(1) \\ A(i)=A_{even}(-1)+iA_{odd}(-1) \\ A(-i)=A_{even}(-1)-iA_{odd}(-1) A(1)=Aeven(1)+Aodd(1)A(1)=Aeven(1)Aodd(1)A(i)=Aeven(1)+iAodd(1)A(i)=Aeven(1)iAodd(1)可以通过在二个点上求 2 个 n − 1 2 \frac{n-1}{2} 2n1 次多项式来求 4 个点上 n − 1 n-1 n1 次多项式的值。

利用对称性(相反数),我们可以实现一穿二的计算速度,换句话说,计算速度翻倍。


3. 离散傅里叶 DFT 和单位根

在这里插入图片描述
单位根(Roots of Unity)是复数域中的一组特殊复数,它们是复数平面上的单位长度向量,分布在圆周上,且相邻单位根之间的夹角相等,相邻单位根之间的夹角为 2 π / n 2π/n 2π/n 弧度。

具体来说,一个 n n n 次单位根是复数 ω \omega ω,满足条件: ω n = 1 \omega^n=1 ωn=1

单位根是使得其 n 次幂等于1的复数

单位根可以用复数的指数形式表示为: ω k = e 2 π i k n ​ \omega_k = e^{\frac{2πik}{n}}​ ωk=en2πik

回到下面这个式子:

给定多项式 a ( x ) = a 0 + a 1 x + … + a n − 1 x n − 1 a (x) = a_0 + a_1x +…+ a_{n-1} x_{n - 1} a(x)=a0+a1x++an1xn1,在 n n n 个不同的点处求值 x 0 , … , x n − 1 x_0,…, x_{n-1} x0,,xn1: [ y 0 y 1 y 2 ⋮ y n − 1 ] = [ 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 ] [ a 0 a 1 a 2 ⋮ a n − 1 ] \begin{bmatrix}y_0\\y_1\\y_2\\\vdots \\y_{n-1}\end{bmatrix} = \begin{bmatrix} 1& x_0& x_0^2 & \dots &x_0^{n-1} \\ 1& x_1& x_1^2 & \dots & x_1^{n-1}\\ 1& x_2& x_2^2 & \dots & x_2^{n-1}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 1& x_{n-1} & x_{n-1}^2 & \dots & x_{n-1}^{n-1} \end{bmatrix}\begin{bmatrix}a_0\\a_1\\a_2\\\vdots\\a_{n-1}\end{bmatrix} y0y1y2yn1 = 1111x0x1x2xn1x02x12x22xn12x0n1x1n1x2n1xn1n1 a0a1a2an1

将其中的 x i x_i xi 用单位根 ω \omega ω 进行替换可得:

[ y 0 y 1 y 2 ⋮ y n − 1 ] = [ 1 1 1 … 1 1 ω 1 ω 2 … ω n − 1 1 ω 2 ω 4 … ω 2 ( n − 1 ) ⋮ ⋮ ⋮ ⋱ ⋮ 1 ω n − 1 ω 2 ( n − 1 ) … ω ( n − 1 ) ( n − 1 ) ] [ a 0 a 1 a 2 ⋮ a n − 1 ] \begin{bmatrix}y_0\\y_1\\y_2\\\vdots \\y_{n-1}\end{bmatrix} =\begin{bmatrix} 1& 1& 1 & \dots &1\\ 1& \omega^1& \omega^2 & \dots & \omega^{n-1}\\ 1& \omega^2& \omega^4 & \dots & \omega^{2(n-1)}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 1& \omega^{n-1} & \omega^{2(n-1)} & \dots & \omega^{(n-1)(n-1)} \end{bmatrix}\begin{bmatrix}a_0\\a_1\\a_2\\\vdots\\a_{n-1}\end{bmatrix} y0y1y2yn1 = 11111ω1ω2ωn11ω2ω4ω2(n1)1ωn1ω2(n1)ω(n1)(n1) a0a1a2an1 其中 y k = A ( ω k ) y_k=A(\omega^k) yk=A(ωk) ω i \omega^i ωi 为傅里叶矩阵。


4. FFT

给定多项式 A ( x ) = a 0 + a 1 x + … + a n − 1 x n − 1 A (x) = a_0 + a_1x +…+ a_{n-1} x_{n - 1} A(x)=a0+a1x++an1xn1,在 n t h n^{th} nth 单位根处求值 ω 0 , ω 1 , … , ω n − 1 \omega^0,\omega^1,…, \omega^{n-1} ω0,ω1,,ωn1

拆解: A e v e n ( x ) = a 0 + a 2 x + a 4 x 2 + . . . + a n − 2 x n / 2 − 1 A o d d ( x ) = a 1 + a 3 x + a 5 x 2 + . . . + a n − 1 x n / 2 − 1 A_{even}(x)=a_0+a_2x+a_4x^2+...+a_{n-2}x^{n/2-1} \\ A_{odd}(x)=a_1+a_3x+a_5x^2+...+a_{n-1}x^{n/2-1} Aeven(x)=a0+a2x+a4x2+...+an2xn/21Aodd(x)=a1+a3x+a5x2+...+an1xn/21 A ( x ) = A e v e n ( x 2 ) + x A o d d ( x 2 ) A ( − x ) = A e v e n ( x 2 ) − x A o d d ( x 2 ) A(x)=A_{even}(x^2)+xA_{odd}(x^2) \\ A(-x)=A_{even}(x^2)-xA_{odd}(x^2) A(x)=Aeven(x2)+xAodd(x2)A(x)=Aeven(x2)xAodd(x2)
求解:求 A e v e n ( x ) A_{even}(x) Aeven(x) A o d d ( x ) A_{odd}(x) Aodd(x)和在单位的 n t h 2 \frac{n^{th}}{2} 2nth 根处的值: v 0 , v 1 , … , v n / 2 − 1 v^0,v^1,…,v^{n/ 2-1} v0v1,,vn/21

合并: y k = A ( ω k ) = A e v e n ( v k ) + ω k A o d d ( v k ) , 0 ≤ k ≤ n / 2 y k + n / 2 = A ( ω k + n / 2 ) = A e v e n ( v k ) − ω k A o d d ( v k ) , 0 ≤ k ≤ n / 2 y_k=A(\omega^k)=A_{even}(v^k)+\omega^kA_{odd}(v^k),0\le k \le n/2 \\ y_{k+n/2}=A(\omega^{k+n/2})=A_{even}(v^k)-\omega^kA_{odd}(v^k),0\le k \le n/2 yk=A(ωk)=Aeven(vk)+ωkAodd(vk),0kn/2yk+n/2=A(ωk+n/2)=Aeven(vk)ωkAodd(vk),0kn/2其中 v k = ( ω k ) 2 , ω k + n / 2 = − ω k v^k=(\omega^k)^2,\omega^{k+n/2}=-\omega^k vk=(ωk)2,ωk+n/2=ωk

在这里插入图片描述
FFT算法在 O ( n l o g n ) O(n log n) O(nlogn) 个算术运算和 O ( n ) O(n) O(n) 个额外空间中,对每个单位的 n n n 次方根计算 n − 1 n - 1 n1 次多项式
T ( n ) = { Θ ( 1 ) if  x = 1 2 T ( n / 2 ) + Θ ( n ) if  x > 1 T(n)=\left\{\begin{matrix} \Theta (1) & \text{if } x=1\\ 2T(n/2)+\Theta (n) & \text{if } x>1 \end{matrix}\right. T(n)={ Θ(1)2T(n/2)+Θ(n)if x=1if x>1


5. Inverse FFT

给定 n n n 个不同的点 x 0 , … , x n − 1 x_0,…, x_{n-1} x0,,xn1 和值 y 0 , … , y n − 1 y_0,…, y_{n - 1} y0,,yn1 ,求唯一多项式 a 0 + a 1 x + … + a n − 1 x n − 1 a_0 + a_1x +…+ a_{n-1} x_ {n-1} a0+a1x++an1xn1 ,在给定的点上有给定的值。 [ y 0 y 1 y 2 ⋮ y n − 1 ] = [ 1 1 1 … 1 1 ω 1 ω 2 … ω n − 1 1 ω 2 ω 4 … ω 2 ( n − 1 ) ⋮ ⋮ ⋮ ⋱ ⋮ 1 ω n − 1 ω 2 ( n − 1 ) … ω ( n − 1 ) ( n − 1 ) ] − 1 [ a 0 a 1 a 2 ⋮ a n − 1 ] \begin{bmatrix}y_0\\y_1\\y_2\\\vdots \\y_{n-1}\end{bmatrix} =\begin{bmatrix} 1& 1& 1 & \dots &1\\ 1& \omega^1& \omega^2 & \dots & \omega^{n-1}\\ 1& \omega^2& \omega^4 & \dots & \omega^{2(n-1)}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 1& \omega^{n-1} & \omega^{2(n-1)} & \dots & \omega^{(n-1)(n-1)} \end{bmatrix}^{-1}\begin{bmatrix}a_0\\a_1\\a_2\\\vdots\\a_{n-1}\end{bmatrix} y0y1y2yn1 = 11111ω1ω2ωn11ω2ω4ω2(n1)1ωn1ω2(n1)ω(n1)(n1) 1 a0a1a2an1

在这里插入图片描述


多项式乘法快速求解

在这里插入图片描述

#include <iostream>
#include <vector>
#include <complex>
#include <cmath>

using namespace std;

typedef complex<double> Complex;

// FFT算法
void fft(vector<Complex>& a, bool invert) {
    
    
    int n = a.size();
    if (n <= 1) return;

    vector<Complex> a0(n / 2), a1(n / 2);
    for (int i = 0, j = 0; i < n; i += 2, j++) {
    
    
        a0[j] = a[i];
        a1[j] = a[i + 1];
    }

    fft(a0, invert);
    fft(a1, invert);

    double ang = 2 * M_PI / n * (invert ? -1 : 1);
    Complex w(1), wn(cos(ang), sin(ang));

    for (int i = 0; i < n / 2; i++) {
    
    
        Complex t = w * a1[i];
        a[i] = a0[i] + t;
        a[i + n / 2] = a0[i] - t;
        if (invert) {
    
    
            a[i] /= 2;
            a[i + n / 2] /= 2;
        }
        w *= wn;
    }
}

// 多项式乘法
vector<int> multiplyPolynomials(vector<int>& poly1, vector<int>& poly2) {
    
    
    int n = 1;
    while (n < poly1.size() + poly2.size() - 1) n *= 2;
    vector<Complex> a(n), b(n);
    
    for (int i = 0; i < poly1.size(); i++) a[i] = poly1[i];
    for (int i = 0; i < poly2.size(); i++) b[i] = poly2[i];
    
    fft(a, false);
    fft(b, false);
    
    for (int i = 0; i < n; i++) a[i] *= b[i];
    
    fft(a, true);
    
    vector<int> result(n);
    for (int i = 0; i < n; i++) result[i] = round(a[i].real());
    return result;
}

int main() {
    
    
    vector<int> poly1 = {
    
    1, 2, 3};
    vector<int> poly2 = {
    
    4, 5, 6};

    vector<int> result = multiplyPolynomials(poly1, poly2);

    cout << "Result: ";
    for (int i = 0; i < result.size(); ++i) {
    
    
        cout << result[i] << " ";
    }
    cout << endl;

    return 0;
}


猜你喜欢

转载自blog.csdn.net/cold_code486/article/details/134130065
今日推荐