【ACM数论】从“快速傅里叶变换 FFT”到“快速数论变换 NTT”

1、FFT前言

FFT全称(Fast Fourier Transformation)快速傅里叶变换

NTT全称(Fast Number Theoretical Transformation)快速数论变换

1.1、引入问题

如何计算多项式 f ( x ) f(x) f(x) g ( x ) g(x) g(x)的乘积?

例如:计算 f ( x ) = 1 + x 2 + x 3 f(x)=1+x^2+x^3 f(x)=1+x2+x3 g ( x ) = 1 + x 5 + x 6 + x 7 g(x)=1+x^5+x^6+x^7 g(x)=1+x5+x6+x7的乘积

通常而言,我们思考暴力的算法:
f ( x ) × g ( x ) = 1 × ( 1 + x 5 + x 6 + x 7 ) + x 2 × ( 1 + x 5 + x 6 + x 7 ) + x 3 × ( 1 + x 5 + x 6 + x 7 ) = 1 + x 5 + x 6 + x 7 + x 2 + x 7 + x 8 + x 9 + x 3 + x 8 + x 9 + x 10 = 1 + x 2 + x 3 + x 5 + x 6 + 2 x 7 + 2 x 8 + 2 x 9 + x 10 \begin{aligned} f(x)\times g(x)&=1\times(1+x^5+x^6+x^7)+x^2\times(1+x^5+x^6+x^7)+x^3\times(1+x^5+x^6+x^7) \\& =1+x^5+x^6+x^7+x^2+x^7+x^8+x^9+x^3+x^8+x^9+x^{10} \\& =1+x^2+x^3+x^5+x^6+2x^7+2x^8+2x^9+x^{10} \end{aligned} f(x)×g(x)=1×(1+x5+x6+x7)+x2×(1+x5+x6+x7)+x3×(1+x5+x6+x7)=1+x5+x6+x7+x2+x7+x8+x9+x3+x8+x9+x10=1+x2+x3+x5+x6+2x7+2x8+2x9+x10
显而易见,这个算法的时间复杂度是 O ( n 2 ) O(n^2) O(n2)

那么有快速的计算方法吗?

当然是有的,于1965年由J.W.库利和T.W.图基提出FFT算法,可以在 O ( n l o g n ) O(nlogn) O(nlogn)的时间复杂度下计算出答案。

1.2、定义一些记号

# f ( x ) f(x) f(x)表示一个多项式

**#**对于一个 n n n次多项式 f ( x ) f(x) f(x)的第 m m m项,记为 f [ m ] f[m] f[m];换言之, f ( x ) = ∑ i = 0 n f [ i ] x i f(x)=\sum_{i=0}^{n}f[i]x^i f(x)=i=0nf[i]xi

1.3、多项式乘法理解

例如:现有两个 n n n次多项式 f ( x ) f(x) f(x) g ( x ) g(x) g(x),需要计算这两个多项式的乘积.

不妨设 h ( x ) = f ( x ) × g ( x ) h(x)=f(x)\times g(x) h(x)=f(x)×g(x)

那么通过1.1中的例子,我们可以发现,其实 h [ k ] = ∑ i = 0 k f [ i ] g [ k − i ] h[k]=\sum_{i=0}^{k}f[i]g[k-i] h[k]=i=0kf[i]g[ki]

换言之,我们可以理解为:要想乘出 x k x^k xk,需要 f ( x ) f(x) f(x) x i x^i xi项和 g ( x ) g(x) g(x) x k − i x^{k-i} xki项相乘,然后将他们的相乘的贡献累加便是 h [ k ] h[k] h[k]

1.4、卷积

将形如: h [ k ] = ∑ i ⊕ j f [ i ] g [ j ] h[k]=\sum_{i⊕j}f[i]g[j] h[k]=ijf[i]g[j]的式子称为卷积,其中⊕在数学中称为假设符号(假设什么运算)

例如,在多项式乘法中,为加法卷积: h [ k ] = ∑ i + j f [ i ] g [ j ] h[k]=\sum_{i+j}f[i]g[j] h[k]=i+jf[i]g[j]

因此,对于卷积可以利用FFT构造多项式进行计算!

2、FFT思想

2.1、多项式的点值表达式

我们可以从

得出推论:在平面直角坐标系中, n + 1 n+1 n+1个点就能唯一确定一个 n n n次多项式。

因此,对于一个 n n n次多项式 f ( x ) f(x) f(x)而言,我们可以用 n + 1 n+1 n+1个点来描述一个多项式;换言之,两个多项式相乘,等价于两个多项式的对应点值相乘。(点值的乘法对应着整个多项式的乘法,也就是浓缩了整个多项式)

将能唯一表达一个 n n n次多项式 f ( x ) f(x) f(x) n + 1 n+1 n+1个点,称为 f ( x ) f(x) f(x)的点值表达式。

$$
例如:n次多项式f(x)的点值表达式为:\

\left{(x_1,f(x_1)),(x_2,f(x_2)),(x_3,f(x_3))…(x_{n+1},f(x_{n+1}))\right}
$$
由于 n n n次多项式 f ( x ) f(x) f(x) n n n次多项式 g ( x ) g(x) g(x),他们的乘积一定是一个 2 n + 1 2n+1 2n+1次的多项式,所以我们只需要对 f ( x ) f(x) f(x) g ( x ) g(x) g(x)找到 2 n + 1 2n+1 2n+1个对应的点,然后将他们对应点的纵坐标相乘,便可以确定多项式 f ( x ) × g ( x ) f(x)\times g(x) f(x)×g(x)的点值表达式;

例如: 2 n + 1 次多项式 f ( x ) × g ( x ) 的点值表达式为: { ( x 1 , f ( x 1 ) g ( x 1 ) ) , ( x 2 , f ( x 2 ) g ( x 2 ) ) , ( x 3 , f ( x 3 ) g ( x 3 ) ) . . . . . . ( x 2 n + 1 , f ( x 2 n + 1 ) g ( x 2 n + 1 ) ) } 例如:2n+1次多项式f(x)\times g(x)的点值表达式为: \\ \left\{(x_1,f(x_1)g(x_1)),(x_2,f(x_2)g(x_2)),(x_3,f(x_3)g(x_3))......(x_{2n+1},f(x_{2n+1})g(x_{2n+1}))\right\} 例如:2n+1次多项式f(x)×g(x)的点值表达式为:{ (x1,f(x1)g(x1)),(x2,f(x2)g(x2)),(x3,f(x3)g(x3))......(x2n+1,f(x2n+1)g(x2n+1))}
最后我们将多项式 f ( x ) × g ( x ) f(x)\times g(x) f(x)×g(x)的点值表达式转化为多项式的一般表达式(系数表达式)便得到了我们想要的多项式乘积了。

而这也是FFT算法的流程

2.2、DFT&IDFT

DFT:把多项式的系数表达式转化为点值表达式的变换过程

IDFT:把多项式的点值表达式转化为系数表达式的变换过程

下面这张图便对比了FFT算法与暴力算法的区别

在这里插入图片描述

3、FFT的实现

3.1、DFT

​ 由于我们想要多项式的点值表达式,所以我们需要利用一些方法获得多项式的上的点;但是细想一下会发现,
如果对于一个 n 次多项式 f ( x ) ,我们任选 n + 1 个点的横坐标 x 1 , x 2 , x 3 . . . . x n , x n + 1 , 再分别计算其对应的纵坐标 f ( x 1 ) , f ( x 2 ) , f ( x 3 ) . . . f ( x n ) , f ( x n + 1 ) 的时间复杂度是 O ( n 2 ) ( 由于计算每个横坐标的时间复杂度是 O ( n ) , 但是有 n 个点 ) ; 如果对于一个n次多项式f(x),我们任选n+1个点的横坐标x_1,x_2,x_3....x_n,x_{n+1},\\再分别计算其对应的纵坐标f(x_1),f(x_2),f(x_3)...f(x_n),f(x_{n+1})的时间复杂度是O(n^2)\\(由于计算每个横坐标的时间复杂度是O(n),但是有n个点); 如果对于一个n次多项式f(x),我们任选n+1个点的横坐标x1,x2,x3....xn,xn+1,再分别计算其对应的纵坐标f(x1),f(x2),f(x3)...f(xn),f(xn+1)的时间复杂度是O(n2)(由于计算每个横坐标的时间复杂度是O(n),但是有n个点)
​ 这样一来,我们通过随便找 n + 1 n+1 n+1个点的方式,会让我们的时间复杂度和暴力没什么区别!

​ 那么有快速找到 n + 1 n+1 n+1个点的方法么?答案当然是有的!

​ 我们可以这样考虑问题:

3.1.1、Good idea 1:函数的奇偶性

​ 首先,我们不考虑一般多项式,只考虑一个简单的多项式 f ( x ) = x 2 f(x)=x^2 f(x)=x2

在这里插入图片描述

那么,如果我们要从 f ( x ) f(x) f(x)中选择8个点,我们如何选择?

这里我们需要注意 f ( x ) f(x) f(x)的一个优美的性质———— f ( x ) f(x) f(x)是偶函数,所以我们计算出一个点 ( x , f ( x ) ) (x,f(x)) (x,f(x))后,便可以立马知道点 ( − x , f ( x ) ) (-x,f(x)) (x,f(x))也一定是 y ( x ) y(x) y(x)上的点。

那么,如果 f ( x ) = x 3 f(x)=x^3 f(x)=x3,应该如何处理喃?

在这里插入图片描述

显而易见,我们会发现 f ( x ) = x 3 f(x)=x^3 f(x)=x3是一个奇函数,它与偶函数的区别在于,奇函数上的点是关于原点对称的,换言之,如果我们计算出点 ( x , f ( x ) ) (x,f(x)) (x,f(x)),那就可以知道点 ( − x , − f ( x ) ) (-x,-f(x)) (x,f(x))也是多项式上的点!

既然这样,对于多项式 f ( x ) = 1 + 2 x 2 + 3 x 3 + 4 x 4 + 5 x 5 f(x)=1+2x^2+3x^3+4x^4+5x^5 f(x)=1+2x2+3x3+4x4+5x5

那么我可以将 f ( x ) f(x) f(x)中按幂数分离,因此可得 f ( x ) = ( 1 + 2 x 2 + 4 x 4 ) + ( 3 x 3 + 5 x 5 ) f(x)=(1+2x^2+4x^4)+(3x^3+5x^5) f(x)=(1+2x2+4x4)+(3x3+5x5)
不妨设 f o ( x ) = 1 + 2 x + 4 x 2 , f e ( x ) = 3 x + 5 x 2 那么有: f ( x ) = ( 1 + 2 x 2 + 4 x 4 ) + x ( 3 x 2 + 5 x 4 ) = f o ( x 2 ) + x f e ( x 2 ) 不妨设f_o(x)=1+2x+4x^2,f_e(x)=3x+5x^2\\ 那么有: \begin{aligned} f(x)&=(1+2x^2+4x^4)+x(3x^2+5x^4) \\&=f_o(x^2)+xf_e(x^2) \end{aligned} 不妨设fo(x)=1+2x+4x2,fe(x)=3x+5x2那么有:f(x)=(1+2x2+4x4)+x(3x2+5x4)=fo(x2)+xfe(x2)
这样,对于 f o ( x 2 ) , f e ( x 2 ) f_o(x^2),f_e(x^2) fo(x2),fe(x2)都是关于 x 2 x^2 x2的多项式,我们便可以利用函数的奇偶性快速找到6个点,然后利用点值表达式的计算方式计算出该函数的点值表达式。

然后我们可以推广到一般多项式 f ( x ) = a 0 + a 1 x + a 2 x 2 + . . . . . a n x n f(x)=a_0+a_1x+a_2x^2+.....a_nx^{n} f(x)=a0+a1x+a2x2+.....anxn
可以设 f ( x ) 按照幂数分离,将偶幂数部分设为 f e ( x 2 ) , 将奇幂数部分提出一个 x 后的部分设为 f o ( x 2 ) 所以: f ( x ) = f e ( x 2 ) + x f o ( x 2 ) 然而对于, f e ( x ) 与 f o ( x ) 而言,最高次都变成了 n 2 − 1 同理可以推出重要结论 { f ( x i ) = f e ( x i 2 ) + x i f o ( x i 2 ) f ( − x i ) = f e ( x i 2 ) − x i f o ( x i 2 ) 这样一来,问题得到了简化: 分别求 f e ( x 2 ) , f o ( x 2 ) 在 x 1 2 , x 2 2 . . . . x n 2 2 的值 , 因为这样我们便可以得到 ± x 1 , ± x 2 . . . ± x n 2 这 n 个点 可以设f(x)按照幂数分离,将偶幂数部分设为f_e(x^2),将奇幂数部分提出一个x后的部分设为f_o(x^2)\\ 所以:f(x)=f_e(x^2)+xf_o(x^2)\\ 然而对于,f_e(x)与f_o(x)而言,最高次都变成了\frac{n}{2}-1\\ 同理可以推出重要结论 \begin{cases} f(x_i)=f_e(x_i^2)+x_if_o(x_i^2)\\ f(-x_i)=f_e(x_i^2)-x_if_o(x_i^2) \end{cases} \\ 这样一来,问题得到了简化: \\分别求f_e(x^2),f_o(x^2)在x_1^2,x_2^2....x_{\frac{n}{2}}^2的值,因为这样我们便可以得到\pm x_1,\pm x_2...\pm x_\frac{n}{2}这n个点 可以设f(x)按照幂数分离,将偶幂数部分设为fe(x2),将奇幂数部分提出一个x后的部分设为fo(x2)所以:f(x)=fe(x2)+xfo(x2)然而对于,fe(x)fo(x)而言,最高次都变成了2n1同理可以推出重要结论{ f(xi)=fe(xi2)+xifo(xi2)f(xi)=fe(xi2)xifo(xi2)这样一来,问题得到了简化:分别求fe(x2),fo(x2)x12,x22....x2n2的值,因为这样我们便可以得到±x1,±x2...±x2nn个点
而对于 f e ( x ) 与 f o ( x ) f_e(x)与f_o(x) fe(x)fo(x),我们可以重复 f ( x ) f(x) f(x)的奇偶分离的方式;这样我们可以把对于 n n n次多项式转化为求 n 2 \frac{n}{2} 2n次多项式(类似分治的思想),所以这个思路下,求多项式点值表达式的时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)

因此,只要我们最后找到的点为合法的点,那么算法就是合法的!

但是这里出现了一个问题:对于 f ( x ) f(x) f(x)中的 [ ± x 1 , ± x 2 . . . ± x n 2 ] [\pm x_1,\pm x_2...\pm x\frac{n}{2}] [±x1,±x

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值