【FFTNTT入门】大整数乘法

news/2024/10/21 7:48:01/

问题:给定两个大整数 A A A B B B A A A B B B 的长度为 n n n m m m,求 A A A B B B 的乘积

1. 朴素做法

思考小学数学中两个数的乘法列竖式的方式,对于 B B B 的每一位,分别乘上 A A A 的每一位,得到的结果相加。

23 × 456 23\times 456 23×456 为例:

23 × 456 = 6 × 3 + 6 × 20 + 50 × 3 + 50 × 20 + 400 × 3 + 400 × 20 = 18 + 120 + 150 + 1000 + 1200 + 8000 = 10488 \begin{aligned} 23\times 456 &= 6\times 3 + 6\times 20+50\times 3+50\times 20+400\times 3+400\times 20\\ &= 18+120+150+1000+1200+8000 \\ &= 10488 \end{aligned} 23×456=6×3+6×20+50×3+50×20+400×3+400×20=18+120+150+1000+1200+8000=10488

如此需要进行 2 × 3 2\times 3 2×3 次乘法以及 2 × 3 − 1 2\times 3 - 1 2×31 次加法。

对于到长度为 n n n 的数 A A A 和长度为 m m m 的数 B B B ,则需要进行 n × m n\times m n×m 次乘法和 n × m − 1 n\times m-1 n×m1 次加法

如此时间复杂度为: O ( n m ) O(nm) O(nm),不妨设 m ≤ n m\leq n mn,则时间复杂度为 O ( n 2 ) O(n^2) O(n2)

2. 快速傅里叶变换

上述的朴素做法时间复杂度过高,当两者长度都达到 1 0 5 10^5 105 级别时,就很难快速得到两个大整数的乘积了。

2.1 求解思想

2.1.1 大整数转换为多项式

考虑将两个大整数转换成多项式:

A ( x ) = a 0 + a 1 x + a 2 x 2 + ⋯ + a n − 1 x n − 1 A(x)=a_0+a_1x+a_2x^2+\cdots+a_{n-1}x^{n-1} A(x)=a0+a1x+a2x2++an1xn1 B ( x ) = b 0 + b 1 x + b 2 x 2 + ⋯ + b m − 1 x m − 1 B(x)=b_0+b_1x+b_2x^2+\cdots+b_{m-1}x^{m-1} B(x)=b0+b1x+b2x2++bm1xm1

以上多项式的表示称为多项式的系数表示法

23 × 456 23\times 456 23×456 为例:

a 0 = 3 , a 1 = 2 a_0=3,a_1=2 a0=3,a1=2 A ( x ) = 3 + 2 x A(x)=3+2x A(x)=3+2x

b 0 = 6 , b 1 = 5 , b 2 = 4 , B ( x ) = 6 + 5 x + 4 x 2 b_0=6,b_1=5,b_2=4, B(x)=6+5x+4x^2 b0=6,b1=5,b2=4,B(x)=6+5x+4x2

可以看出:

23 23 23 可以转换为 a 0 = 3 , a 1 = 2 a_0=3,a_1=2 a0=3,a1=2 的多项式, A ( 10 ) = 23 A(10)=23 A(10)=23

456 456 456 可以转换为 b 0 = 6 , b 1 = 5 , b 2 = 4 b_0=6,b_1=5,b_2=4 b0=6,b1=5,b2=4 的多项式,当 B ( 10 ) = 456 B(10)=456 B(10)=456

那么 A ( 10 ) × B ( 10 ) A(10)\times B(10) A(10)×B(10) 即为 23 × 456 23\times 456 23×456 的结果

问题转换成了求解两个多项式 A ( x ) A(x) A(x) B ( x ) B(x) B(x) 的乘积

C ( x ) = A ( x ) × B ( x ) = c 0 + c 1 x + c 2 x 2 + ⋯ + c n + m − 2 x n + m − 2 C(x)=A(x)\times B(x) = c_0+c_1x+c_2x^2+\cdots + c_{n+m-2}x^{n+m-2} C(x)=A(x)×B(x)=c0+c1x+c2x2++cn+m2xn+m2

c k = ∑ i + j = k a i × b j c_k=\sum\limits_{i+j=k} a_i\times b_{j} ck=i+j=kai×bj

c k c_k ck 的过程也称为卷积,整体的时间复杂度也为 O ( n 2 ) O(n^2) O(n2)

2.1.2 多项式的点值表示法

上述将大整数转换为多项式的系数表示法进行多项式的计算,时间复杂度仍未改进。

事实上,多项式还有另外一种表示法,即点值表示法。

我们思考一条直线 y = k x + b y=kx+b y=kx+b,如果转换为上述表达,即为: A ( x ) = a 0 + a 1 x A(x)=a_0+a_1x A(x)=a0+a1x,其中 a 0 = b , a 1 = k a_0=b,a_1=k a0=b,a1=k。而两点确定一条直线,则我们如果找出两个不同点,计算出斜率 k k k 和截距 b b b ,则唯一确定一条直线,即唯一确定一个一阶多项式。

推广到更高阶的多项式,对于 n n n 阶多项式 A ( x ) = ∑ i = 0 n a i x i A(x)=\sum\limits_{i=0}^n a_ix^i A(x)=i=0naixi,如果找到 n + 1 n+1 n+1 个不同点,则可以唯一确定一个 n n n 阶多项式。二维平面上 n + 1 n+1 n+1 个不同点可以唯一确定一个 n n n 阶多项式)。

对于多项式 A ( x ) A(x) A(x),其点值表示法为: { ( x 0 , A ( x 0 ) ) , ( x 1 , ( A ( x 1 ) ) , ⋯ , ( x n , A ( x n ) ) } \{(x_0,A(x_0)),(x_1,(A(x_1)),\cdots,(x_n,A(x_n))\} {(x0,A(x0)),(x1,(A(x1)),,(xn,A(xn))}

要证明 n n n 阶多项式可以由 n + 1 n+1 n+1 个点唯一确定,只需要证明这 n + 1 n+1 n+1 个系数是唯一的

对于 A ( x ) = a 0 + a 1 x + a 2 x 2 + ⋯ + a n x n A(x)=a_0+a_1x+a_2x^2+\cdots+a_nx^n A(x)=a0+a1x+a2x2++anxn

n + 1 n+1 n+1 个点带入多项式,得到 n + 1 n+1 n+1 个方程

A ( x 0 ) = a 0 + a 1 x 0 + a 2 x 0 2 + ⋯ + a n x 0 n A(x_0)=a_0+a_1x_0+a_2x_0^2+\cdots+a_nx_0^n A(x0)=a0+a1x0+a2x02++anx0n

A ( x 1 ) = a 0 + a 1 x 1 + a 2 x 1 2 + ⋯ + a n x 1 n A(x_1)=a_0+a_1x_1+a_2x_1^2+\cdots+a_nx_1^n A(x1)=a0+a1x1+a2x12++anx1n

⋯ \cdots

A ( x n ) = a 0 + a 1 x n + a 2 x n 2 + ⋯ + a n x n n A(x_n)=a_0+a_1x_n+a_2x_n^2+\cdots+a_nx_n^n A(xn)=a0+a1xn+a2xn2++anxnn

写成矩阵形式:

[ A ( x 0 ) A ( x 1 ) ⋮ A ( x d ) ] = [ 1 x 0 x 0 2 ⋯ x 0 n 1 x 1 x 1 2 ⋯ x 1 n ⋮ ⋮ ⋮ ⋱ ⋮ 1 x n x n 2 ⋯ x n n ] [ a 0 a 1 ⋮ a n ] \left[\begin{array}{c} A\left(x_{0}\right) \\ A\left(x_{1}\right) \\ \vdots \\ A\left(x_{d}\right) \end{array}\right]=\left[\begin{array}{ccccc} 1 & x_{0} & x_{0}^{2} & \cdots & x_{0}^{n} \\ 1 & x_{1} & x_{1}^{2} & \cdots & x_{1}^{n} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 1 & x_{n} & x_{n}^{2} & \cdots & x_{n}^{n} \end{array}\right]\left[\begin{array}{c} a_{0} \\ a_{1} \\ \vdots \\ a_{n} \end{array}\right] A(x0)A(x1)A(xd) = 111x0x1xnx02x12xn2x0nx1nxnn a0a1an

令方阵为矩阵 M M M M M M 也称为范德蒙德矩阵, x 0 , x 1 , ⋯ , x n x_0,x_1,\cdots,x_n x0,x1,,xn 两两不同。证明 n + 1 n+1 n+1 个系数唯一只需要证明 M M M 的行列式不为 0 0 0 即可,而范德蒙德行列式的值一定不为 0 0 0,故得证二维平面上 n + 1 n+1 n+1 个不同点可以唯一确定一个 n n n 阶多项式

至此,对于对于 n n n 阶多项式 A ( x ) = ∑ i = 0 n a i x i A(x)=\sum\limits_{i=0}^n a_ix^i A(x)=i=0naixi,我们有两种多项式表示法:

  • 系数表示法,给出 n + 1 n+1 n+1 个系数

[ a 0 , a 1 , ⋯ , a n ] [a_0,a_1,\cdots,a_n] [a0,a1,,an]

  • 点值表示法,给出 n + 1 n+1 n+1 个点

    { ( x 0 , A ( x 0 ) ) , ( x 1 , ( A ( x 1 ) ) , ⋯ , ( x n , A ( x n ) ) } \{(x_0,A(x_0)),(x_1,(A(x_1)),\cdots,(x_n,A(x_n))\} {(x0,A(x0)),(x1,(A(x1)),,(xn,A(xn))}

2.1.3 多项式乘积的计算流程

对于两个多项式, A ( x ) = ∑ i = 0 n a i x i A(x)=\sum\limits_{i=0}^n a_ix^i A(x)=i=0naixi B ( x ) = ∑ i = 0 m b i x i B(x)=\sum\limits_{i=0}^m b_ix^i B(x)=i=0mbixi
两个多项式的乘积为 C ( x ) = A ( x ) ⋅ B ( x ) = ∑ i = 0 m + n c i x i C(x)=A(x)\cdot B(x)=\sum\limits_{i=0}^{m+n}c_ix^i C(x)=A(x)B(x)=i=0m+ncixi 共有 n + m + 1 n+m+1 n+m+1

因此对于多项式 A ( x ) A(x) A(x) B ( x ) B(x) B(x) 各取 n + m + 1 n+m+1 n+m+1 个点

对于 A ( x ) A(x) A(x),取点为: { ( x 0 , A ( x 0 ) ) , ( x 1 , ( A ( x 1 ) ) , ⋯ , ( x n + m , A ( x n + m ) ) } \{(x_0,A(x_0)),(x_1,(A(x_1)),\cdots,(x_{n+m},A(x_{n+m}))\} {(x0,A(x0)),(x1,(A(x1)),,(xn+m,A(xn+m))}

对于 B ( x ) B(x) B(x),取点为: { ( x 0 , B ( x 0 ) ) , ( x 1 , ( B ( x 1 ) ) , ⋯ , ( x n + m , B ( x n + m ) ) } \{(x_0,B(x_0)),(x_1,(B(x_1)),\cdots,(x_{n+m},B(x_{n+m}))\} {(x0,B(x0)),(x1,(B(x1)),,(xn+m,B(xn+m))}

得到的 C ( x ) C(x) C(x) n + m + 1 n+m+1 n+m+1 个点为:

{ ( x 0 , A ( x 0 ) × B ( x 0 ) ) , ( x 1 , ( A ( x 1 ) × B ( x 1 ) ) , ⋯ , ( x n + m , A ( x n + m × B ( x n + m ) ) ) } \{(x_0,A(x_0)\times B(x_0)),(x_1,(A(x_1)\times B(x_1)),\cdots,(x_{n+m},A(x_{n+m}\times B(x_{n+m})))\} {(x0,A(x0)×B(x0)),(x1,(A(x1)×B(x1)),,(xn+m,A(xn+m×B(xn+m)))}

该乘积的时间复杂度为: O ( n ) O(n) O(n)

如何得到 C ( x ) C(x) C(x) 的系数表示法呢?

  • A ( x ) A(x) A(x) B ( x ) B(x) B(x) 从系数表示法转换成点值表示法 A ( x ) A(x) A(x) B ( x ) B(x) B(x) 中各取 n + m + 1 n+m+1 n+m+1 个点, 这 n + m + 1 n+m+1 n+m+1 个点的横坐标对应相同
  • O ( n ) O(n) O(n) 时间计算出每个点的纵坐标乘积,即得到表示 C ( x ) C(x) C(x) n + m + 1 n+m+1 n+m+1 个点
  • C ( x ) C(x) C(x) 从点值表示法转换成系数表示法

2.2 求解流程

2.2.1 从系数表示到点值表示(FFT)

朴素做法

A ( x ) A(x) A(x) B ( x ) B(x) B(x) 中各取 n + m + 1 n+m+1 n+m+1 个点,对于每个点,选择其横坐标后,通过系数表示法计算出其对应的纵坐标,需要的时间复杂度为 O ( n ) O(n) O(n),总时间复杂度为 O ( n 2 ) O(n^2) O(n2),因此时间复杂度不满足要求。

快速傅立叶变换(Fast Fourier Transform)是一种快速进行离散傅立叶变换的方法, 通过单位根的性质, 将 n n n 次求值的时间复杂度降为 O ( n log ⁡ n ) O(n \log n) O(nlogn)

F F T \mathrm{FFT} FFT n n n 保证为 2 2 2 的幂

A ( x ) → a = [ a 0 , a 1 , a 2 , ⋯ , a n − 1 ] ⊤ A(x) \rightarrow a=\left[a_{0}, a_{1}, a_{2}, \cdots, a_{n-1}\right]^{\top} A(x)a=[a0,a1,a2,,an1] , 将其分为偶数项和奇数项两个向量

偶 a [ 0 ] = [ a 0 , a 2 , ⋯ , a n − 2 ] 奇 a [ 1 ] = [ a 1 , a 3 , ⋯ , a n − 1 ] 偶 a^{[0]}=\left[a_{0}, a_{2}, \cdots, a_{n-2}\right]\\ 奇 a^{[1]}=\left[a_{1}, a_{3}, \cdots, a_{n-1}\right] a[0]=[a0,a2,,an2]a[1]=[a1,a3,,an1]

A ( x ) = a 0 + a 1 x + a 2 x 2 + ⋯ + a n − 1 x n − 1 A [ 0 ] ( x ) = a 0 + a 2 x + a 4 x 2 + ⋯ + a n − 2 x n 2 − 1 A [ 1 ] ( x ) = a 1 + a 3 x + a 5 x 2 + ⋯ + a n − 1 x n 2 − 1 \begin{array}{l} A(x)=a_{0}+a_{1} x+a_{2} x^{2}+\cdots+a_{n-1}^{x} n-1 \\ A^{[0]}(x)=a_{0}+a_{2} x+a_{4} x^{2}+\cdots+a_{n-2} x^{\frac{n}{2}-1} \\ A^{[1]}(x)=a_{1}+a_{3} x+a_{5} x^{2}+\cdots+a_{n-1} x^{\frac{n}{2}-1} \end{array} A(x)=a0+a1x+a2x2++an1xn1A[0](x)=a0+a2x+a4x2++an2x2n1A[1](x)=a1+a3x+a5x2++an1x2n1

A [ 0 ] ( x 2 ) = a 0 + a 2 x 2 + a 4 x 4 + ⋯ + a n − 2 x n − 2 A [ 1 ] ( x 2 ) = a 1 + a 3 x 2 + a 5 x 4 + ⋯ + a n − 1 x n − 2 x A [ 1 ] ( x 2 ) = a 1 x + a 3 x 3 + a 5 x 5 + ⋯ + a n − 1 x n − 1 \begin{array}{l} A^{[0]}\left(x^{2}\right)=a_{0}+a_{2} x^{2}+a_{4} x^{4}+\cdots+a_{n-2} x^{n-2} \\ A^{[1]}\left(x^{2}\right)=a_{1}+a_{3} x^{2}+a_{5} x^{4}+\cdots+a_{n-1} x^{n-2} \\ x A^{[1]}\left(x^{2}\right)=a_{1} x+a_{3} x^{3}+a_{5} x^{5}+\cdots+a_{n-1} x^{n-1} \end{array} A[0](x2)=a0+a2x2+a4x4++an2xn2A[1](x2)=a1+a3x2+a5x4++an1xn2xA[1](x2)=a1x+a3x3+a5x5++an1xn1

那么有: $A(x)=A{[0]}\left(x{2}\right)+x A{[1]}\left(x{2}\right) $

原问题: 求 A ( x ) A(x) A(x) 在每个单位根上的值
转化为: 求次数界为 n 2 \frac{n}{2} 2n 的两个多项式 A [ 0 ] ( x ) A^{[0]}(x) A[0](x) A [ 1 ] ( x ) A^{[1]}(x) A[1](x) 在每个单位根平方上的值, 再合并。

A ( w n k ) = A [ 0 ] ( ( w n k ) 2 ) + w n k A [ 1 ] ( ( w n k ) 2 ) A ( ω n k + n 2 ) = A [ 0 ] ( ( ω n k + n 2 ) 2 ) + ω n k + n 2 A [ 1 ] ( ( ω n k + n 2 ) 2 ) \begin{array}{l} A\left(w_{n}^{k}\right)=A^{[0]}\left(\left(w_{n}^{k}\right)^{2}\right)+w_{n}^{k} A^{[1]}\left(\left(w_{n}^{k}\right)^{2}\right) \\ A\left(\omega_{n}^{k+\frac{n}{2}}\right)=A^{[0]}\left(\left(\omega_{n}^{k+\frac{n}{2}}\right)^{2}\right)+\omega_{n}^{k+\frac{n}{2}} A^{[1]}\left(\left(\omega_{n}^{k+\frac{n}{2}}\right)^{2}\right) \end{array} A(wnk)=A[0]((wnk)2)+wnkA[1]((wnk)2)A(ωnk+2n)=A[0]((ωnk+2n)2)+ωnk+2nA[1]((ωnk+2n)2)

通过消去引理折半引理, 将上式化简为:

A ( ω n k ) = A [ 0 ] ( ω n 2 k ) + ω n k A [ 1 ] ( ω n 2 k ) A ( ω n k + n 2 ) = A [ 0 ] ( ω n 2 k ) − ω n k A [ 1 ] ( ω n 2 k ) \begin{array}{ll} & A\left(\omega_{n}^{k}\right)=A^{[0]}\left(\omega_{\frac{n}{2}}^{k}\right)+\omega_{n}^{k} A^{[1]}\left(\omega_{\frac{n}{2}}^{k}\right) \\ & A\left(\omega_{n}^{k+\frac{n}{2}}\right)=A^{[0]}\left(\omega_{\frac{n}{2}}^{k}\right)-\omega_{n}^{k} A^{[1]}\left(\omega_{\frac{n}{2}}^{k}\right) \end{array} A(ωnk)=A[0](ω2nk)+ωnkA[1](ω2nk)A(ωnk+2n)=A[0](ω2nk)ωnkA[1](ω2nk)

A [ 0 ] ( x ) A^{[0]}(x) A[0](x) A [ 1 ] ( x ) A^{[1]}(x) A[1](x) 恰好均为次数界为 n 2 \frac{n}{2} 2n 的多项式

DFT ⁡ n ( a ) = { D F T n 2 ( a [ 0 ] ) DFT ⁡ n 2 ( a [ 1 ] ) \operatorname{DFT}_{n}(a)=\left\{\begin{array}{l} \mathrm{DFT}_{\frac{n}{2}}\left(a^{[0]}\right) \\ \operatorname{DFT}_{\frac{n}{2}}\left(a^{[1]}\right) \end{array}\right. DFTn(a)={DFT2n(a[0])DFT2n(a[1])

所以问题又转化为了求 次数界为 n 2 \frac{n}{2} 2n 的多项式 A [ 0 ] ( x ) A^{[0]}(x) A[0](x) A [ 1 ] ( x ) A^{[1]}(x) A[1](x)
这两个问题和原问题的描述类似, 原问题的次数界为 n n n , 子问题的次数界为 n 2 \frac{n}{2} 2n , 所以这两个问题是范围缩小一 半的两个子问题, 通过同样的方式求解这两个子问题, 那么就是熟悉的递归求解了。再根据折半引理, 就可以快速 地合并结果。

T ( n ) = 2 T ( n 2 ) + O ( n ) T(n)=2 T\left(\frac{n}{2}\right)+O(n) T(n)=2T(2n)+O(n)

根据主定理, 时间复杂度为: O ( n log ⁡ n ) O(n \log n) O(nlogn)

2.2.2 点值表示的乘积

对于 A ( x ) A(x) A(x),取点为: { ( x 0 , A ( x 0 ) ) , ( x 1 , ( A ( x 1 ) ) , ⋯ , ( x n + m , A ( x n + m ) ) } \{(x_0,A(x_0)),(x_1,(A(x_1)),\cdots,(x_{n+m},A(x_{n+m}))\} {(x0,A(x0)),(x1,(A(x1)),,(xn+m,A(xn+m))}

对于 B ( x ) B(x) B(x),取点为: { ( x 0 , B ( x 0 ) ) , ( x 1 , ( B ( x 1 ) ) , ⋯ , ( x n + m , B ( x n + m ) ) } \{(x_0,B(x_0)),(x_1,(B(x_1)),\cdots,(x_{n+m},B(x_{n+m}))\} {(x0,B(x0)),(x1,(B(x1)),,(xn+m,B(xn+m))}

得到的 C ( x ) C(x) C(x) n + m + 1 n+m+1 n+m+1 个点为:

{ ( x 0 , A ( x 0 ) × B ( x 0 ) ) , ( x 1 , ( A ( x 1 ) × B ( x 1 ) ) , ⋯ , ( x n + m , A ( x n + m × B ( x n + m ) ) ) } \{(x_0,A(x_0)\times B(x_0)),(x_1,(A(x_1)\times B(x_1)),\cdots,(x_{n+m},A(x_{n+m}\times B(x_{n+m})))\} {(x0,A(x0)×B(x0)),(x1,(A(x1)×B(x1)),,(xn+m,A(xn+m×B(xn+m)))}

该乘积的时间复杂度为: O ( n ) O(n) O(n)

2.2.3 从点值表示到系数表示(IFFT)

朴素做法

已知 n + 1 n+1 n+1 个点组成的多项式点值表示 { x 0 , A ( x 0 ) , ( x 1 , A ( x 1 ) ) , … , ( x n , A ( x n ) ) } \{x_0,A(x_0),(x_1,A(x_1)),\ldots,(x_n,A(x_n))\} {x0,A(x0),(x1,A(x1)),,(xn,A(xn))},求 A ( x ) A(x) A(x) 的过程叫作插值

拉格朗日插值公式计算: A ( x ) = ∑ i = 0 n A ( x i ) ∏ j ≠ i ( x − x j ) ∏ j ≠ i ( x i − x j ) A(x)=\sum\limits_{i=0}^n A(x_i)\frac{\prod\limits_{j\neq i}(x-x_j)}{\prod\limits_{j\neq i}(x_i-x_j)} A(x)=i=0nA(xi)j=i(xixj)j=i(xxj)

时间复杂度: O ( n 2 ) O(n^2) O(n2)

顾名思义,快速傅里叶逆变换(Inverse Fast Fourier Transform)是快速傅里叶变换的逆。

D F T → y i = ∑ j = 0 n − 1 w n i j a j → y = V n a \mathrm{DFT} \rightarrow y_i=\sum\limits_{j=0}^{n-1}w_n^{ij}a_j\rightarrow y=V_n a DFTyi=j=0n1wnijajy=Vna

V n = [ 1 1 1 ⋯ 1 1 ω n ω n 2 ⋯ ω n n − 1 1 ω n 2 ω n 4 ⋯ ω n 2 ( n − 1 ) ⋮ ⋮ ⋮ ⋱ ⋮ 1 ω n n − 1 ω n 2 ( n − 1 ) ⋯ ω n ( n − 1 ) ( n − 1 ) ] V_n=\begin{bmatrix} 1 & 1 & 1 & \cdots & 1 \\ 1 & \omega_n & \omega_n^2 & \cdots & \omega_n^{n-1} \\ 1 & \omega_n^2 & \omega_n^4 & \cdots & \omega_n^{2(n-1)}\\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 1 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \cdots & \omega_{n}^{(n-1)(n-1)} \\ \end{bmatrix} Vn= 11111ωnωn2ωnn11ωn2ωn4ωn2(n1)1ωnn1ωn2(n1)ωn(n1)(n1)

这里的 V n V_{n} Vn 是一个范德蒙德矩阵, 它的第 i i i 行第 j j j 列尾主 n n n 次单位根的 i j i j ij 次方

( V n ) i j = ω n i j \left(V_{n}\right)_{i j}=\omega_{n}^{i j} (Vn)ij=ωnij

离散傅立叶变换给出 a a a y y y , 而离散傅立叶逆变换给出 y y y a a a , 所以要用 V n V_{n} Vn 的逆矩阵乘向量 y y y , 即 a = V n − 1 y a=V_{n}^{-1} y a=Vn1y , 其中

( V n − 1 ) i j = ω n − i j n \left(V_{n}^{-1}\right)_{i j}=\frac{\omega_{n}^{-i j}}{n} (Vn1)ij=nωnij

( V n − 1 V n ) i j = ∑ k = 0 n − 1 ω n − k i n × ω n k j = ∑ k = 0 n − 1 ω n k ( j − i ) n \left(V_{n}^{-1} V_{n}\right)_{i j}=\sum_{k=0}^{n-1} \frac{\omega_{n}^{-k i}}{n} \times \omega_{n}^{k j}=\sum_{k=0}^{n-1} \frac{\omega_{n}^{k(j-i)}}{n} (Vn1Vn)ij=k=0n1nωnki×ωnkj=k=0n1nωnk(ji)

当且仅当 i = j i=j i=j 时, ( V n − 1 V n ) i j = 1 \left(V_{n}^{-1} V_{n}\right)_{i j}=1 (Vn1Vn)ij=1 , 其余情况 ( V n − 1 V n ) i j = 0 \left(V_{n}^{-1} V_{n}\right)_{i j}=0 (Vn1Vn)ij=0 , 所以结果是一个单位矩阵, 即 V n − 1 V n = I n V_{n}^{-1} V_{n}=I_{n} Vn1Vn=In , 所以 ( V n − 1 ) i j = ω n − i j n \left(V_{n}^{-1}\right)_{i j}=\frac{\omega_{n}^{-i j}}{n} (Vn1)ij=nωnij 得证

可以发现

I D F T → a i = V n − 1 y = ∑ j = 0 n − 1 ω n − i j n = 1 n ∑ j = 0 n − 1 ω n − i j y j D F T → y i = ∑ j = 0 n − 1 ω n i j a j \begin{array}{l} \mathrm{IDFT} \rightarrow a_{i}=V_{n}^{-1} y=\sum_{j=0}^{n-1} \frac{\omega_{n}^{-i j}}{n}=\frac{1}{n} \sum_{j=0}^{n-1} \omega_{n}^{-i j} y_{j} \\ \mathrm{DFT} \rightarrow y_{i}=\sum_{j=0}^{n-1} \omega_{n}^{i j} a_{j} \end{array} IDFTai=Vn1y=j=0n1nωnij=n1j=0n1ωnijyjDFTyi=j=0n1ωnijaj

F F T \mathrm{FFT} FFT 中的 ω n = e 2 π n i = cos ⁡ ( 2 π n ) + i sin ⁡ ( 2 π n ) \omega_{n}=e^{\frac{2 \pi}{n} i}=\cos \left(\frac{2 \pi}{n}\right)+i \sin \left(\frac{2 \pi}{n}\right) ωn=en2πi=cos(n2π)+isin(n2π)
改成 ω n = e − 2 π n i = cos ⁡ ( 2 π n ) − i sin ⁡ ( 2 π n ) \omega_{n}=e^{-\frac{2 \pi}{n} i}=\cos \left(\frac{2 \pi}{n}\right)-i \sin \left(\frac{2 \pi}{n}\right) ωn=en2πi=cos(n2π)isin(n2π)
如此, 对 F F T \mathrm{FFT} FFT 做部分修改即可由点值表示转换为系数表示,由于仅参数不同,故时间复杂度仍为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

3. 快速数论变换

之前介绍了FFT,一种利用复数性质加速多项式乘积运算的算法

可以发现,在计算时,实部和虚部因为需要使用 c o s cos cos s i n sin sin 以及 π \pi π,必须存储为浮点形式,复数的乘法运算也较为复杂。

计算机中的浮点数不免存在精度误差问题,所以我们考虑是否存在一种整数域内的形式,将复数转换为实数?

3.1 部分概念

3.1.1 欧拉函数

欧拉函数 φ ( n ) \varphi(n) φ(n) 表示小于等于 n n n 的数中与 n n n 互质的数的个数

3.1.2 欧拉定理

gcd ⁡ ( a , n ) = 1 \operatorname{gcd}(a,n)=1 gcd(a,n)=1 ,存在 a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi (n)} \equiv 1(\bmod\ n) aφ(n)1(mod n)

3.1.3 费马小定理

p p p 是质数,欧拉定理为 a p − 1 ≡ 1 ( m o d p ) a^{p-1} \equiv 1(\bmod\ p) ap11(mod p)

费马小定理就是欧拉定理的特殊形式

3.1.4 阶

由欧拉定理可知, 对 a ∈ Z , m ∈ N ∗ a \in \mathbb{Z}, m \in \mathbb{N}^{*} aZ,mN , 若 gcd ⁡ ( a , m ) = 1 \operatorname{gcd}(a, m)=1 gcd(a,m)=1 , 则 a φ ( m ) ≡ 1 ( m o d m ) a^{\varphi(m)} \equiv 1(\bmod m) aφ(m)1(modm) 。因此满足同余式 a n ≡ 1 ( m o d m ) a^{n} \equiv 1(\bmod m) an1(modm) 的最小正整数 n n n 存在, 这个 n n n 称作 a a a m m m 的阶, 记作 δ m ( a ) \delta_{m}(a) δm(a)

3.1.5 原根

a a a m m m 的阶为 φ ( m ) \varphi(m) φ(m) ,即 δ m ( a ) = φ ( m ) \delta_{m}(a)=\varphi(m) δm(a)=φ(m) ,则称 a a a 为模 m m m 的原根

3.2 用原根代替复数根

复数根: ω n k = ( e 2 π n i ) k \omega_{n}^k=(e^{\frac{2\pi}{n}i})^k ωnk=(en2πi)k

用原根来替代复数根的每个实数根: g n k = ( G p − 1 n ) k m o d p g_n^k=(G^{\frac{p-1}{n}})^k \bmod \ p gnk=(Gnp1)kmod p

对原根而言:

g n n = g p − 1 = g φ ( p ) = 1 ≡ ( m o d p ) g n n / 2 = g ( p − 1 ) / 2 \begin{array}{l} g_{n}^{n}=g^{p-1}=g^{\varphi(p)}=1 \equiv(\bmod p) \\ g_{n}^{n / 2}=g^{(p-1) / 2} \end{array} gnn=gp1=gφ(p)=1(modp)gnn/2=g(p1)/2

而:

( g ( p − 1 ) / 2 ) 2 ≡ g p − 1 ≡ 1 ( m o d p ) \left(g^{(p-1) / 2}\right)^{2} \equiv g^{p-1} \equiv 1(\bmod p) (g(p1)/2)2gp11(modp)

即求方程 x 2 ≡ 1 ( m o d p ) x^{2} \equiv 1(\bmod p) x21(modp) , 在 p p p 为素数时只有 ± 1 \pm 1 ±1 两种取值。由于 g g g 是原根, 只有 g n n ≡ 1 ( m o d p ) g_{n}^{n} \equiv 1(\bmod p) gnn1(modp) , 故 g ( p − 1 ) / 2 ≡ − 1 ( m o d p ) g^{(p-1) / 2} \equiv-1(\bmod p) g(p1)/21(modp)

原根满足:

  • 具有周期性
  • 一个周期内的数均不相同
  • g n k = − g n k + n / 2 g_{n}^{k}=-g_{n}^{k+n / 2} gnk=gnk+n/2

如此我们就找到了一个可以替换复数根的实数根,常用原根模数 9982442353 9982442353 9982442353,原根为 3 3 3,因为 998244352 = 2 23 ⋅ 7 ⋅ 17 998244352=2^{23}\cdot 7 \cdot 17 998244352=223717

因为 2 23 = 8388608 2^{23}=8388608 223=8388608,对于长度在 8 × 1 0 6 8\times 10^6 8×106 内的大整数乘法足够使用。

4. 提交

从 LeetCode Multiply Strings 一题的提交结果来看:

  • FFT 的递归版本比 FFT 的迭代版本需要更多的运行时间和空间。这是因为 FFT 的递归版本会使用额外的栈空间用来辅助计算,开辟和回收这些空间也需要一定的时间,因此相较于 FFT 的迭代版本,FFT 的递归版本的运行时间和空间消耗更多
  • NTT 的迭代版本比 FFT 的迭代版本需要的运行时间和空间都更少。这是因为 NTT 使用的是原根,相较于单位复根需要的空间更少,计算次数也更少。

总体来说,FFT 和 NTT 的时间复杂度是相同的,均为 O ( n log ⁡ n ) O(n\log n) O(nlogn)。NTT 在一定大小范围内的大整数乘法运算中不论是空间还是时间都好过于 FFT,计算的常数低于 FFT ,精度也高于 FFT ,唯一的问题是需要找到合适的原根保证可以覆盖运算需要的范围,当寻找到的原根可以覆盖需要的运算范围,可以选择 NTT ,否则就选择 FFT。

5. 补充

5.1 复数

形如 z = a + b i z=a+bi z=a+bi 的数称为复数,其中: a , b ∈ R , i 2 = − 1 , i a,b\in R,\ i^2=-1,i a,bR, i2=1,i 虚数单位

复数的幅角表示形式: z = r e i θ z=r\mathcal{e}^{i\theta} z=reiθ r r r 为模长, θ \theta θ 为幅角

加法法则: ( a + b i ) + ( c + d i ) = a + c + ( b + d ) i (a+bi)+(c+di)=a+c+(b+d)i (a+bi)+(c+di)=a+c+(b+d)i

减法法则: ( a + b i ) − ( c + d i ) = a − c + ( b − d ) i (a+bi)-(c+di)=a-c+(b-d)i (a+bi)(c+di)=ac+(bd)i

乘法法则: ( a + b i ) × ( c + d i ) = a c + a d i + b c i + b d i 2 = a c − b d + ( a d + b c ) i (a+bi)\times (c+di)=ac+adi+bci+bdi^2=ac-bd+(ad+bc)i (a+bi)×(c+di)=ac+adi+bci+bdi2=acbd+(ad+bc)i

除法法则: ( a + b i ) ÷ ( c + d i ) = a + b i c + d i = a c + b d + ( b c − a d ) i c 2 − d 2 (a+bi)\div (c+di)=\frac{a+bi}{c+di}=\frac{ac+bd+(bc-ad)i}{c^2-d^2} (a+bi)÷(c+di)=c+dia+bi=c2d2ac+bd+(bcad)i

欧拉定理: e i θ = cos ⁡ θ + i sin ⁡ θ e^{i\theta}=\cos\theta+i\sin\theta eiθ=cosθ+isinθ

任意一个复数 a + b i a+bi a+bi 对应复平面上的一个点 ( a , b ) (a,b) (a,b) ,横坐标为实部,纵坐标为虚部。

模长 r r r 即复平面上对应的点到原点的距离,即 a 2 + b 2 \sqrt{a^2+b^2} a2+b2

幅角 θ \theta θ 即复平面上对应的点到原点的连线与 x x x 轴的夹角

5.2 单位根

z = a + b i = r e i θ = r ( cos ⁡ θ + i sin ⁡ θ ) z=a+bi=re^{i\theta}=r(\cos\theta+i\sin\theta) z=a+bi=reiθ=r(cosθ+isinθ)

两个复数相乘的结果为:两个复数的模相乘,再乘以 e 幅角的和 e^{幅角的和} e幅角的和

单位根是方程 z n = 1 z^n=1 zn=1 在复数范围内的 n n n 个根,因为是单位根,因此模长 r r r 1 1 1,本质就是求解 n n n 个不同的 θ \theta θ,使得每个 θ \theta θ 对应的 z z z 都有 z n = 1 z^n=1 zn=1

z n = r n e n θ i = 1 ⇒ { r = 1 n θ = 2 k π z^n=r^ne^{n\theta i}=1\\\Rightarrow \left\{\begin{array}{l} r=1\\ n\theta =2k\pi \end{array}\right. zn=rnenθi=1{r=1nθ=2

所以 ω n = 1 \omega^n=1 ωn=1 n n n 个根为: ω n k = e i 2 k π n = cos ⁡ 2 k π n + i sin ⁡ 2 k π n , ( k = 0 , 1 , 2 , . . . , n − 1 ) \omega_n^k=e^{i\frac{2k\pi}{n}}=\cos\frac{2k\pi}{n}+i\sin\frac{2k\pi}{n},(k=0,1,2,...,n-1) ωnk=ein2=cosn2+isinn2,(k=0,1,2,...,n1)

n n n 次单位根 ω n = e i 2 π n \omega_n=e^{i\frac{2\pi}{n}} ωn=ein2π

5.2.1 消去引理

ω d n d k = ω n k \omega_{dn}^{dk}=\omega_n^k ωdndk=ωnk

证明: ω d n d k = ( e 2 π d n i ) d k = ( e 2 π n i ) k = ω n k \omega_{dn}^{dk}=(e^{\frac{2\pi}{dn} i})^{dk}=(e^{\frac{2\pi}{n}i})^k=\omega_n^k ωdndk=(edn2πi)dk=(en2πi)k=ωnk

5.2.2 折半引理

( w n k + n 2 ) 2 = ( ω n k ) 2 = ω n 2 k (w_n^{k+\frac{n}{2}})^2=(\omega_n^k)^2=\omega_{\frac{n}{2}}^k (wnk+2n)2=(ωnk)2=ω2nk

证明: ω n k + n 2 = ω n k ω n n 2 = − ω n k \omega_n^{k+\frac{n}{2}}=\omega_n^k\omega_n^{\frac{n}{2}}=-\omega_n^k ωnk+2n=ωnkωn2n=ωnk ,其中 ω n n 2 = ω 2 = − 1 \omega_n^{\frac{n}{2}}=\omega_2=-1 ωn2n=ω2=1 ( ω n k ) 2 = ω n 2 k = ω n 2 k (\omega_n^k)^2=\omega_n^{2k}=\omega_{\frac{n}{2}}^k (ωnk)2=ωn2k=ω2nk

5.2.3 求和引理

∑ i = 0 n − 1 ( ω n k ) i = 0 \sum\limits_{i=0}^{n-1}(\omega_n^k)^i=0 i=0n1(ωnk)i=0

证明: ∑ i = 0 n − 1 ( ω n k ) i = ( ω n k ) n − 1 ω n k − 1 = ( ω n n ) k − 1 ω n k − 1 = 1 k − 1 ω n k − 1 = 0 \sum\limits_{i=0}^{n-1}(\omega_n^k)^i=\frac{(\omega_n^k)^n-1}{\omega_n^k-1}=\frac{(\omega_n^n)^k-1}{\omega_n^k-1}=\frac{1^k-1}{\omega_n^k-1}=0 i=0n1(ωnk)i=ωnk1(ωnk)n1=ωnk1(ωnn)k1=ωnk11k1=0

5.3 参考视频和博客

1. 课程PPT

2. 快速傅里叶变换(FFT)——有史以来最巧妙的算法?

3. 算法学习笔记(42): 快速数论变换

4. 快速数论变换(NTT)超详解


http://www.ppmy.cn/news/305997.html

相关文章

CKA 04_部署 harbor 仓库 containerd 连接 harbor 仓库 kubeadm 引导集群

文章目录 1. 清空之前的策略1.1 kubeadm 重置1.2 刷新 IPtables 表 2. 查看 Kubernetes 集群使用的镜像3. 搭建 harbor 仓库3.1 部署 docker3.1.1 准备镜像源3.1.2 安装 docker3.1.3 开机自启 docker3.1.4 修改内核参数,打开桥接3.1.5 验证生效 3.2 准备 harbor 仓库…

WD西部数据2TB,2.5寸移动硬盘,因为磁头坏了,长时间通电导致划片划伤,维修过程通过反复更换磁头

WD西部数据2TB,2.5寸移动硬盘,因为磁头坏了,长时间通电导致划片划伤,维修过程通过反复更换磁头,才能利用专业设备,里面找到,镜像,把内容数据恢复出来。 1.说一下经历,借用…

矿盘上手记-三星pm981a(持续更新)

首先,为什么? 答,作为小米忠实用户,本质上生活在21世纪的一个穷比ds,买东西最注重性价比,什么东西便宜又大碗,又有需要,我就冲冲冲! 2022年5月11日,在淘宝上…

自己组装硬盘服务器,气吞山河,25硬盘组装超级存储服务器全案!

现在硬盘真是便宜啊,便宜得让许多“小菜”都敢冒一句:“唐华,你给我算算装个2T的机子要多钱?”两T?!就是2000G啊。这过去一般人谁玩得起啊,现在呢,四个500G硬盘搞定,真是…

小米路由器r1d刷第三方_好物推荐 篇三:服役多年的小米路由器R1D准备让他退休, 小米路由R3D开始上岗...

好物推荐 篇三:服役多年的小米路由器R1D准备让他退休, 小米路由R3D开始上岗 2019-06-27 22:25:00 11点赞 26收藏 41评论 你是AMD Yes党?还是intel和NVIDIA的忠实簇拥呢?最新一届#装机大师赛#开始啦!本次装机阵营赛分为3A红组、intel NVIDIA蓝绿组、混搭组还有ITX组,实体o…

五大主流云盘横评对比,百度、腾讯、115、iCloud、OneDrive哪家更值得付费?

五大主流云盘横评对比,百度、腾讯、115、iCloud、OneDrive哪家更值得付费? 前言各大云盘免费服务对比各大云盘付费服务对比照片视频备份文件历史版本各家云盘会员购买建议百度网盘腾讯微云115网盘iCloudOneDrive 云盘安全吗?结尾 前言 互联网…

2021-08-17

这份保姆级Kafka两万字指南,图文并茂,看完你都明白了 2021-08-06 10:00Java码农之路 1、为什么有消息系统 1、解耦合 2、异步处理 例如电商平台,秒杀活动。 一般流程会分为: 风险控制库存锁定生成订单短信通知更新数据 通…

计算机组成原理笔记(王道考研) 第三章:存储系统

内容基于中国大学MOOC的2023考研计算机组成原理课程所做的笔记。 感谢LY,他帮我做了一部分笔记。由于听的时间不一样,第四章前的内容看起来可能稍显啰嗦,后面会记得简略一些。 西电的计算机组织与体系结构课讲法和王道考研的课不太一样&…