FFT主要用於快速求多項式的乘積。多項式的乘積就叫做卷積
對\(F\)和\(G\)來說,顯然暴力演算法的複雜度是\(O(nm)\),而FFT的時間複雜度為\(O(nlogn)\)
多項式的性質:用任意\(n+1\)個橫座標不同的點,可以唯一確定一個\(n\)次多項式。這個性質叫做多項式的點表示法
證明:設這個多項式\(f=a_nx^n+a_{n-1}x^{n-1}+...+a_1x+a_0\),那麼我們代入\(n+1\)個點可以獲得\(n+1\)個方程,這是\(n+1\)元一次方程,寫出係數行列式就會發現是範德蒙德行列式,由於橫座標不同,所以行列式的值不為\(0\),於是方程有唯一解
設\(H=FG\),於是\(H\)為\(n+m\)次多項式,我們選取\(n+m+1\)個點代入\(F,G\)之後即可確定\(H\)。這就是點表示法的好處,時間複雜度從\(O(nm)\)降低到了\(O(n+m)\)
於是我們現在要解決的問題是如何快速將一個多項式的係數表示法(也就是我們通常寫出來的多項式)與點表示法互相轉換
下文的\(f(x)=a_{n-1}x^{n-1}+...+a_1x+a_0\)
係數表示法轉點表示法:我們要在取\(n+1\)個特殊點上下功夫,我們取複數域上的單位根
假設\(n\)是偶數,畫出複數域上的單位圓:
設\(w_n^k\)表示將單位圓等分成\(n\)份,將\(x\)軸逆時針旋轉\(\frac{2πk}{n}\)所得到的複數,其中\(k\)的取值為\([0,n-1]\)。比如上圖,\(w_n^0=1\),\(w_n^3=-i\)
\(w_n^k\)具有如下的性質:
1.\(\forall i\neq j,w_n^i\neq w_n^j\)
2.\(w_n^k=\cos(\frac{2kπ}{n})+i\sin(\frac{2kπ}{n})\)
3.\(w_{2n}^{2k}=w_n^k\)
4.\(w_n^{k+\frac{n}{2}}=-w_n^k\)
現在,我們將\(f\)奇數項和偶數項分開,有\(f=g+h\),其中\(g(x)=a_{n-2}x^{n-2}+a_{n-4}x^{n-4}+...+a_2x^2+a_0,h=a _ {n-1} x ^ {n-1} + a _ {n-3}x^{n-3}+...+a_1x\)
將\(g\)中每個\(x\)用\(x^2\)代替可設\(φ_1(x)=a_{n-2}x^{\frac{n}{2}-1}+a_{n-4}x^{\frac{n}{2}-2}+...+a_2x+a_0\),將\(h\)提取一個\(x\)並將剩下的式子的\(x\)用\(x^2\)代替可得\(φ_2(x)=a_{n-1}x^{\frac{n}{2}-1}+a_{n-3}x^{\frac{n}{2}-2}+...+a_1\),於是\(f(x)=φ_1(x^2)+xφ_2(x^2)\)
現在,設\(k∈[0,\frac{n}{2}-1]\),則\(f(w_n^k)=φ_1(w_n^{2k})+w_n^kφ_2(w_n^{2k})=φ_1(w_{\frac{n}{2}}^{k})+w_n^kφ_2(w_{\frac{n}{2}}^{k}),f(w_n^{k+\frac{n}{2}})=φ_1(w_n^{2k})-w_n^kφ_2(w_n^{2k})=φ_1(w_{\frac{n}{2}}^{k})-w_n^kφ_2(w_{\frac{n}{2}}^{k})\)
也就是說我們要求出將\(w_n^0,w_n^1,...,w_n^{n-1}\)代入\(f\)的值,只需要遞迴求解\(φ_1,φ_2\)即可;一共會劃分\(O(\log n)\)層,每層的總複雜度為\(O(n)\),所以時間複雜度為\(O(n\log n)\)(如果某一次\(n\)為奇數,我們最開始提出一個\(x\)即可)
點表示法轉換為係數表示法:設我們現在已經知道了\((w_n^0,f(w_n^0)),...,(w_n^{n-1},f(w_n^{n-1}))\),我們要求\(f(x)\),則有\(a_k=\frac{\sum_{i=0}^{n-1}f(w_n^{i})(w_n^{-k})^i}{n}\)
證明:
,最後一步成立是因為
於是我們設\(\rho(x)=\sum_{i=0}^{n-1}f(w_n^{i})x^{i}\),則我們求出\(\rho(w_n^{0}),\rho(w_n^{-1}),...,\rho(w_n^{-(n-1)})\)即可,這就是上文講的傅立葉正變換(係數表示法轉化為點表示法)
最後講一下實現。實踐證明,如果用遞迴來實現的話,常數是非常大的,所以我們一般利用迭代來實現
影片看到了2:08:00