P3803 【模板】多项式乘法(FFT)。
多项式基础知识
点值表示法
一个 n 次多项式可以被 (xi,yi) 这种的 n+1 个点表示。
比较显然的。
FFT 就是利用这种性质,来求解答案。我们需要一个快速将系数表示法转换成点表示法的东西。
复数
这里面还需要一些复数的性质,先看看复数相乘:
(a+bi)∗(c+di)=ac+adi+bci+bdi2=ac+adi+bci−bd=(ac−bd)+(bc+ad)i
为了方便说明,n 先设为 2 的整次幂。在复平面上,以单位圆的 n 等分点为终点,做 n 个向量,ωn2,ωn3,…,ωnn。
性质:
ωnk=ω2n2k
ωnn=1ωn2n=−1
z2=(a+bi)2=a2+2abi+(bi)2=a2−b2+2abiz2=(cos2θ−sin2θ,2cosθsinθ)=(cos2θ,sin2θ)
快速傅里叶变换
正变换
A(x)=a0+a1∗x+a2∗x2+a3∗x3+a4∗x4+a5∗x5+⋯+an−2∗xn−2+an−1∗xn−1
按照奇偶性拆分:
A1(x)=a0+a2∗x+a4∗x2+⋯+an−2∗x2n−1
A2(x)=a1∗x+a3∗x+a5∗x2+⋯+an−1∗x2n−1
所以:
A(x)=A1(x2)+xA2(x2)
A(ωnk)=A1(ωn2k)+ωnkA2(ωn2k)
A(ωnk+2n)=A1(ωn2k+n)+ωnk+2n(ωn2k+n)=A1(ωn2k×ωnn)−ωnkA2(ωn2k×ωnn)=A1(ωn2k)−ωnkA2(ωn2k)
--
对比这两个式子:
A(ωnk)=A1(ωn2k)+ωnkA2(ωn2k)
A(ωnk+2n)=A1(ωn2k)−ωnkA2(ωn2k)
所以我们枚举第一个式子的时候可以 O(1) 计算第二个式子的值。
逆变换
-
系数 → 点值(DFT,正变换)
-
点值 → 系数(IDFT,逆变换)
我们还需要一个逆变换。
nA(x)=c0+c1x+c2x2+⋯+cn−1xn−1ak=nck
ck=i=0∑n−1yi(ωn−k)i
B(x)=y0+y1x+y2x2+⋯+yn−1xn−1
ck=B(ωn−k)
怎么证明?
将 yi=∑j=0n−1ajωnij 代入 ck:
ck=i=0∑n−1(j=0∑n−1ajωnij)ωn−ik=j=0∑n−1aji=0∑n−1ωni(j−k)
内层和式 S=∑i=0n−1(ωnj−k)i 是等比数列求和:
- 若 j=k,则 ωn0=1,S=n
- 若 j=k,则 ωnj−k=1,且 (ωnj−k)n=1,由等比数列求和公式得:
S=1−ωnj−k1−(ωnj−k)n=1−ωnj−k1−1=0
因此 ck=ak⋅n,即 ak=ck/n。证毕。
所以逆变换公式就是:
ak=n1i=0∑n−1yiωn−ik
公式整合
-
正变换(DFT):
yk=∑j=0n−1ajωnjk
-
逆变换(IDFT):
aj=n1∑k=0n−1ykωn−jk
也就是逆变换只需要把正变换的 ω 取一个相反数就行了。
A(ωnk+2n)=A1(ωn2k)−ωnkA2(ωn2k)
小优化:
我们可以把 b(x) 放到 a(x) 的虚部上去,求出a(x)2,然后把 a(x) 的虚部取出来除 2 就是答案了。
(a+bi)2=(a2−b2)+(2abi)
这样就只需要 3 次 FFT 了。
P4245 【模板】任意模数多项式乘法
P4245 【模板】任意模数多项式乘法。
我们发现如果直接用 FFT 中 double 精度不够,1023 完全不行。
A(x)=A0(x)⋅M+A1(x),B(x)=B0(x)⋅M+B1(x)
A⋅B=(A0B0)M2+(A0B1+A1B0)M+A1B1
我们只需要用 4 次 FFT 递归下去(显然递推也行),求出这四个值加起来。
Pk=(A0)k(B0)k+i⋅(A1)k(B0)kQk=(A0)k(B1)k+i⋅(A1)k(B1)k
这样的话只有不到 1014 次。