FFT & NTT 複習筆記

lnw143發表於2024-06-22

快速變換

設原多項式為 \(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 \]

構造單位根

  • FFT

在複數域下,有 \(\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> 儲存複數。

  • NTT

對於模數 \(P \in \mathbb P, \exist n,k \in \mathbb Z^+, P=2^nk+1\),在模 \(P\) 意義下有 \(\omega _n \equiv g ^ {\frac {P-1} n}\),其中 \(g\) 是原根。

相關文章