快速變換
設原多項式為 \(F(x) = \sum_{i \in [0,n)} a_i x ^ i\),其中 \(n = 2 ^ k, k \in \mathbb Z ^ +\)。
我們要求 \(\forall i \in [0,n),\hat a_i = F(t_i)\),其中 \(t\) 是一個長度為 \(n\) 且兩兩互不相同的序列。
顯然 \(F\) 可以被一組 \(\hat a,t\) 唯一確定,即點值表示法。
另設兩個多項式
\[G_0(x)=a_0 + a_2 x + \dots + a_{n - 2} x^{\frac n 2 - 1} \\
G_1(x)=a_1 + a_3 x + \dots + a_{n - 1} x^{\frac n 2 - 1} \\
\]
則有
\[\begin{aligned}
F(x) & = \sum_{i \in [0,n)} a_i x ^ i \\
& = a_0 + a_1 x + a_2 x^2 + \dots + a_{n-1} x^{n-1} \\
& = (a_0 + a_2 x^2 + \dots + a_{n-2} x^{n-2}) + (a_1 x + a_3 x^3 + \dots + a_{n-1} x^{n-1}) \\
& = G_0 (x ^ 2) + x G_1 (x ^ 2) \\
\end{aligned}
\]
考慮構造單位根 \(\omega _n ^k\) 滿足 \(\omega _n ^{\frac n 2} = -1, \omega _{2n} ^ {2k} = \omega _n ^k\)。
顯然也有 \(\omega _n ^n = \omega _n ^0 = 1\)。
設 \(\forall i \in [0,n), t_i = \omega _n ^i\)。
當 \(x = \omega _n ^k, k \in [0,\frac n 2)\) 時顯然有
\[\begin{aligned}
F(\omega _n ^k) & = G_0(\omega _n ^{2k}) + \omega _n ^k G_1(\omega _n ^{2k}) \\
& = G_0(\omega _ {\frac n 2} ^ k) + \omega _n ^k G_1(\omega _{\frac n 2} ^k) \\
\end{aligned}
\]
當 \(x = \omega _n ^{k + \frac n 2}, k \in [0,\frac n 2)\) 時有
\[\begin{aligned}
F(\omega _n ^{k + \frac n 2}) & = G_0(\omega _n ^{2k + n}) + \omega _n ^{k + \frac n 2} G_1(\omega _n ^{2k + n}) \\
& = G_0(\omega _n ^{2k} \cdot \omega _n ^n) - \omega _n ^k G_1(\omega _n ^{2k} \cdot \omega _n ^n) \\
& = G_0(\omega _n ^{2k}) - \omega _n ^k G_1(\omega _n ^{2k}) \\
& = G_0(\omega _{\frac n 2} ^k) - \omega _n ^k G_1(\omega _{\frac n 2} ^k) \\
\end{aligned}
\]
由於兩者只有一個符號的差異,於是 \(F\) 的點值可以直接 \(\mathrm O(n)\) 從 \(G_0, G_1\) 的點值得到。
遞迴解決,時間複雜度 \(\mathrm O(n \log n)\)。
逆變換
設變換後的點值序列為 \(\hat a\),即
\[\begin{aligned}
\forall i \in [0,n), \hat a_i & = F(\omega _n ^i) \\
& = \sum _{j \in [0,n)} a_j (\omega _n ^i)^j \\
& = \sum _{j \in [0,n)} a_j \omega _n ^{ij} \\
\end{aligned}
\]
設多項式 \(\hat F(x) = \sum _{i \in [0,n)} \hat a_i x^i\)。
對 \(\hat F\) 進行點值變換(\(\forall i \in [0,n),t_i = \omega _n ^{-i}\)),設點值序列為 \(s\)。
則有
\[\begin{aligned}
\forall i \in [0,n), s_i & = \hat F(\omega _n ^{-i}) \\
& = \sum _{j \in [0,n)} \hat a_j (\omega _n ^{-i}) ^j \\
& = \sum _{j \in [0,n)} \omega _n ^{-ij} \hat a_j \\
& = \sum _{j \in [0,n)} \omega _n ^{-ij} \sum _{k \in [0,n)} a_k \omega _n ^{jk} \\
& = \sum _{j \in [0,n), k \in [0,n)} \omega _n ^{-ij} a_k \omega _n ^{jk} \\
& = \sum _{j \in [0,n), k \in [0,n)} \omega _n ^{j(k-i)} a_k \\
& = \sum _{k \in [0,n)} a_k \sum _{j \in [0,n)} \omega _n ^{j(k-i)} \\
& = \sum _{k \in [0,n)} a_k \sum _{j \in [0,n)} (\omega _n ^{k-i}) ^j \\
\end{aligned}
\]
顯然第二個求和是一個等比數列,由等比數列求和公式 \(\sum _{i \in [m,n)} p^i = \frac {p^m - p^n} {1 - p}\) 得:
- 當 \(\omega _n ^{k-i} \not = 1 \iff i \not = k\)
\[\begin{aligned}
\sum _{j \in [0,n)} (\omega _n ^{k-i}) ^j & = \frac {1 - \omega _n ^{(k-i) n}} {1 - \omega _n ^{k-i}} \\
& = \frac {1 - (\omega _n ^{k-i}) ^n} {1 - \omega _n ^{k-i}} \\
& = \frac {1 - 1} {1 - \omega _n ^{k-i}} \\
& = 0
\end{aligned}
\]
- 當 \(\omega _n ^{k-i} = 1 \iff i = k\)
\[\sum _{j \in [0,n)} (\omega _n ^{k-i}) ^j = \sum _{j \in [0,n)} 1 = n
\]
因此
\[\begin{aligned}
\forall i \in [0,n), s_i & = \sum _{k \in [0,n)} a_k \sum _{j \in [0,n)} (\omega _n ^{k-i}) ^j \\
& = n a_i \\
\end{aligned}
\]
於是我們有
\[\forall i \in [0,n), a_i = \frac {s_i} n
\]
構造單位根
在複數域下,有 \(\omega _n = \cos \frac {2 \pi} n + \mathrm i \sin \frac {2 \pi} {n}\)。
其中 \(\mathrm i = \sqrt {-1}\) 是 虛數單位,可以用 C++
中的 complex
庫中的 std::complex<double/long double>
儲存複數。
對於模數 \(P \in \mathbb P, \exist n,k \in \mathbb Z^+, P=2^nk+1\),在模 \(P\) 意義下有 \(\omega _n \equiv g ^ {\frac {P-1} n}\),其中 \(g\) 是原根。