高速フーリエ変換を図で理解する
問題
次多項式 について、 での値を計算したい。
(※ ただし とおいた。)
愚直に計算するとかかるが、これをで計算する方法を考える。
アルゴリズム
簡単のため、以降 をの冪乗とする。
次多項式 を以下で定義する。
すると、 が成り立つ。
今 での の値を求めたいので、
について の値が求まっていれば良い。
実は
より、 であることがわかる。
つまり について が求まっていれば良い。
(※ 以下にの場合の図を示す。 は添字が2づつ進んで2周するため、●における の値が求まっていれば良いことがわかる。)
したがって、以下の再帰的な計算で 次多項式 に対する を求めることができる。
各呼び出しで扱う多項式は、の場合以下の図のようになる。 ただし、 から定義した2つの多項式をそれぞれ と表記した。 再帰の終端において、 になっていることがわかる。 次節の実装ではこれを利用している。
計算量はマージソートと同様の解析で となる (分割統治法)。
実装
using Complex = std::complex<double>; struct FFT { std::vector<Complex> a_; int n; FFT(const std::vector<Complex>& a) : a_(a), n(1) { // n を2の冪乗にする while (n < a.size()) n <<= 1; a_.resize(n); }; std::vector<Complex> solve() { return fft(0, 0); } std::vector<Complex> fft(int d, int bit) { int sz = n >> d; if (sz == 1) return {a_[bit]}; auto f0 = fft(d+1, bit); auto f1 = fft(d+1, bit | 1<<d); std::vector<Complex> f(sz); for (int i = 0; i < sz; ++i) { Complex x = std::polar(1.0, 2*M_PI / sz * i); f[i] = f0[i % (sz / 2)] + x * f1[i % (sz / 2)]; } return f; } };