DFT
把系数表示把转化为点值表示法。
有多项式 f n ( x ) = ∑ i = 0 n − 1 a i x i f_n(x)=\sum_{i=0}^{n-1}a_{i}x^{i} fn(x)=∑i=0n−1aixi,其中 n n n是一个 2 2 2的幂,现在要快速求出 ∀ i , 0 ≤ i < n \forall i,0 \le i <n ∀i,0≤i<n的 f ( ω n i ) f(\omega_{n}^{i}) f(ωni)。
首先把 f n ( x ) f_n(x) fn(x)的系数按照奇偶性分成两组,分别为 h n 2 ( x ) = ∑ i = 0 n 2 − 1 a 2 i x i h_{\frac{n}{2}}(x)=\sum_{i=0}^{\frac{n}{2}-1}a_{2i}x^i h2n(x)=∑i=02n−1a2ixi和 g n 2 ( x ) = ∑ i = 0 n 2 − 1 a 2 i + 1 x i g_{\frac{n}{2}}(x)=\sum_{i=0}^{\frac{n}{2}-1}a_{2i+1}x^i g2n(x)=∑i=02n−1a2i+1xi
那么把
f
n
(
ω
n
i
)
f_n(\omega_{n}^{i})
fn(ωni)拆一下,就有如下:
f
n
(
ω
n
i
)
=
∑
j
=
0
n
2
−
1
a
2
j
(
ω
n
i
)
2
j
+
∑
j
=
0
n
2
−
1
a
2
j
+
1
(
ω
n
i
)
2
j
+
1
=
∑
j
=
0
n
2
−
1
a
2
j
(
ω
n
2
i
)
j
+
∑
j
=
0
n
2
−
1
a
2
j
+
1
(
ω
n
2
i
)
j
ω
n
i
=
∑
j
=
0
n
2
−
1
a
2
j
(
ω
n
2
i
)
j
+
∑
j
=
0
n
2
−
1
a
2
j
+
1
(
ω
n
2
i
)
j
ω
n
i
=
h
n
2
(
ω
n
2
i
)
+
ω
n
i
g
n
2
(
ω
n
2
i
)
\begin{aligned} f_n(\omega_{n}^{i}) & = \sum_{j=0}^{\frac{n}{2}-1}a_{2j}(\omega_{n}^{i})^{2j}+\sum_{j=0}^{\frac{n}{2}-1}a_{2j+1}(\omega_{n}^{i})^{2j+1} \\ & = \sum_{j=0}^{\frac{n}{2}-1}a_{2j}(\omega_{n}^{2i})^{j}+\sum_{j=0}^{\frac{n}{2}-1}a_{2j+1}(\omega_{n}^{2i})^{j}\omega_{n}^{i} \\ & = \sum_{j=0}^{\frac{n}{2}-1}a_{2j}(\omega_{\frac{n}{2}}^{i})^{j}+\sum_{j=0}^{\frac{n}{2}-1}a_{2j+1}(\omega_{\frac{n}{2}}^{i})^{j}\omega_{n}^{i} \\ & = h_{\frac{n}{2}}(\omega_{\frac{n}{2}}^{i})+\omega_{n}^{i}g_{\frac{n}{2}}(\omega_{\frac{n}{2}}^{i}) \end{aligned}
fn(ωni)=j=0∑2n−1a2j(ωni)2j+j=0∑2n−1a2j+1(ωni)2j+1=j=0∑2n−1a2j(ωn2i)j+j=0∑2n−1a2j+1(ωn2i)jωni=j=0∑2n−1a2j(ω2ni)j+j=0∑2n−1a2j+1(ω2ni)jωni=h2n(ω2ni)+ωnig2n(ω2ni)
发现
g
,
h
g,h
g,h和
f
f
f是类似的,那么可以分治处理。
然后发现位置的变换是蝴蝶变换,就可以非递归计算了。
蝴蝶变换
可以发现在分治过程中,位置 i i i的值会唯一的变换到 i ′ i' i′的位置,那么可否快速计算,然后从低到高合并呢?这样就可以降低常数。
当然是可以的, i ′ i' i′的二进制表达式和 i i i的二进制表达式是前后对调的,证明就不写了。
IDFT
把点值化为系数表示法。
假设现在要做多项式乘法 C ( x ) = A ( x ) B ( x ) C(x)=A(x)B(x) C(x)=A(x)B(x),那么可以把他们都拓展到 ( n − 1 ) (n-1) (n−1)次的多项式,其中 n n n是 2 2 2的幂。接着对 A ( x ) , B ( x ) A(x),B(x) A(x),B(x)做 D F T DFT DFT,将其转化为点值表示法,那么对于带入的 n n n个 ω n i \omega_{n}^{i} ωni,都有 C ( ω n i ) = A ( ω n i ) B ( ω n i ) C(\omega_{n}^{i})=A(\omega_{n}^{i})B(\omega_{n}^{i}) C(ωni)=A(ωni)B(ωni),就是把对应位置的点值乘到一块就好了,然后对其做 I D F T IDFT IDFT即可。
假设
C
(
x
)
=
∑
i
=
0
n
−
1
a
i
x
i
C(x)=\sum_{i=0}^{n-1}a_ix^i
C(x)=∑i=0n−1aixi,
y
i
=
C
(
ω
n
i
)
y_i=C(\omega_{n}^{i})
yi=C(ωni),那么有如下的矩阵乘法:
[
1
1
1
1
⋯
1
1
ω
n
1
ω
n
2
ω
n
3
⋯
ω
n
n
−
1
1
ω
n
2
ω
n
4
ω
n
6
⋯
ω
n
2
(
n
−
1
)
1
ω
n
3
ω
n
6
ω
n
9
⋯
ω
n
3
(
n
−
1
)
⋮
⋮
⋮
⋮
⋱
⋮
1
ω
n
n
−
1
ω
n
2
(
n
−
1
)
ω
n
3
(
n
−
1
)
⋯
ω
n
(
n
−
1
)
2
]
[
a
0
a
1
a
2
a
3
⋮
a
n
−
1
]
=
[
y
0
y
1
y
2
y
3
⋮
y
n
−
1
]
\begin{bmatrix}1 & 1 & 1 & 1 & \cdots & 1 \\ 1 & \omega_n^1 & \omega_n^2 & \omega_n^3 & \cdots & \omega_n^{n-1} \\ 1 & \omega_n^2 & \omega_n^4 & \omega_n^6 & \cdots & \omega_n^{2(n-1)} \\ 1 & \omega_n^3 & \omega_n^6 & \omega_n^9 & \cdots & \omega_n^{3(n-1)} \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots \\ 1 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \omega_n^{3(n-1)} & \cdots & \omega_n^{(n-1)^2} \end{bmatrix} \begin{bmatrix} a_0 \\ a_1 \\ a_2 \\ a_3 \\ \vdots \\ a_{n-1} \end{bmatrix} = \begin{bmatrix}y_0 \\ y_1 \\ y_2 \\ y_3 \\ \vdots \\ y_{n-1} \end{bmatrix}
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡1111⋮11ωn1ωn2ωn3⋮ωnn−11ωn2ωn4ωn6⋮ωn2(n−1)1ωn3ωn6ωn9⋮ωn3(n−1)⋯⋯⋯⋯⋱⋯1ωnn−1ωn2(n−1)ωn3(n−1)⋮ωn(n−1)2⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤⎣⎢⎢⎢⎢⎢⎢⎢⎡a0a1a2a3⋮an−1⎦⎥⎥⎥⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎢⎢⎢⎡y0y1y2y3⋮yn−1⎦⎥⎥⎥⎥⎥⎥⎥⎤
只要两边都乘上这个方阵的逆矩阵就好了,然后我们发现它的逆矩阵就是对应每一项取倒数并再除以
n
n
n,如下:
1
n
[
1
1
1
1
⋯
1
1
ω
n
−
1
ω
n
−
2
ω
n
−
3
⋯
ω
n
−
(
n
−
1
)
1
ω
n
−
2
ω
n
−
4
ω
n
−
6
⋯
ω
n
−
2
(
n
−
1
)
1
ω
n
−
3
ω
n
−
6
ω
n
−
9
⋯
ω
n
−
3
(
n
−
1
)
⋮
⋮
⋮
⋮
⋱
⋮
1
ω
n
−
(
n
−
1
)
ω
n
−
2
(
n
−
1
)
ω
n
−
3
(
n
−
1
)
⋯
ω
n
−
(
n
−
1
)
2
]
\frac{1}{n} \begin{bmatrix} 1 & 1 & 1 & 1 & \cdots & 1 \\ 1 & \omega_n^{-1} & \omega_n^{-2} & \omega_n^{-3} & \cdots & \omega_n^{-(n-1)} \\ 1 & \omega_n^{-2} & \omega_n^{-4} & \omega_n^{-6} & \cdots & \omega_n^{-2(n-1)} \\ 1 & \omega_n^{-3} & \omega_n^{-6} & \omega_n^{-9} & \cdots & \omega_n^{-3(n-1)} \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots \\ 1 & \omega_n^{-(n-1)} & \omega_n^{-2(n-1)} & \omega_n^{-3(n-1)} & \cdots & \omega_n^{-(n-1)^2} \end{bmatrix}
n1⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡1111⋮11ωn−1ωn−2ωn−3⋮ωn−(n−1)1ωn−2ωn−4ωn−6⋮ωn−2(n−1)1ωn−3ωn−6ωn−9⋮ωn−3(n−1)⋯⋯⋯⋯⋱⋯1ωn−(n−1)ωn−2(n−1)ωn−3(n−1)⋮ωn−(n−1)2⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤
那么现在来证明:
对于乘完之后的方阵,第 i i i行第 i i i列的值可任意这样计算: ∑ k = 0 n − 1 ω n i ω n − i = ∑ k = 0 n − 1 ω n 0 = n \sum_{k=0}^{n-1} \omega_{n}^{i}\omega_{n}^{-i}=\sum_{k=0}^{n-1}\omega_{n}^{0}=n ∑k=0n−1ωniωn−i=∑k=0n−1ωn0=n
对于第 i i i行 j j j列,其中 i ≠ j i \not = j i=j,可以这样计算: ∑ k = 0 n − 1 ( ω n i − j ) k = ( ω n i − j ) n − ( ω n i − j ) 0 ω n i − j − 1 = 0 \sum_{k=0}^{n-1}(\omega_{n}^{i-j})^{k}=\frac{(\omega_{n}^{i-j})^n-(\omega_{n}^{i-j})^0}{\omega_{n}^{i-j}-1}=0 ∑k=0n−1(ωni−j)k=ωni−j−1(ωni−j)n−(ωni−j)0=0
再乘上矩阵前面的 1 n \frac{1}{n} n1,那么逆矩阵就得证了,于是又是一个 D F T DFT DFT。这次的系数是计算出来的点值,带入的是 ω n − i \omega_{n}^{-i} ωn−i,最后把 1 n \frac{1}{n} n1乘进去就好了。
#include<bits/stdc++.h>
using namespace std;
const int N=1<<22;
typedef complex<double> comp;
comp f[N],g[N],h[N];
int r[N];
int nf,ng,nh=1;
void FFT(comp *f,int rev){//rev=1->DFT rev=-1->IDFT
for (int i=0;i<nh;++i) if (r[i]<i) swap(f[i],f[r[i]]);
for (int l=2;l<=nh;l<<=1){
for (int i=0;i<nh;i+=l){
comp step=comp(cos(2.0*M_PI/l),sin(2.0*M_PI/l)*rev),mul=comp(1,0);
for (int j=0;j<(l>>1);++j){
comp tmp=f[i+j+(l>>1)];
f[i+j+(l>>1)]=f[i+j]-mul*tmp;
f[i+j]=f[i+j]+mul*tmp;
mul=mul*step;
}
}
}
}
int main(){
scanf("%d%d",&nf,&ng);
while (nh-1<nf+ng)
nh<<=1;
for (int i=0;i<=nf;++i){double x;scanf("%lf",&x);f[i]=comp(x,0);}
for (int i=0;i<=ng;++i){double x;scanf("%lf",&x);g[i]=comp(x,0);}
r[0]=0;
for (int i=1;i<nh;++i) r[i]=(r[i>>1]>>1)|(i&1?(nh>>1):0);
FFT(f,1);
FFT(g,1);
for (int i=0;i<nh;++i) h[i]=f[i]*g[i];
FFT(h,-1);
for (int i=0;i<=nf+ng;++i) printf("%d ",(int)round(h[i].real()/nh));
}