參考:
如果公式炸了請去我的csdn部落格:
原文即是一篇很好的fft入門部落格,但是筆者打算為了日後的學習,則將原篇章的結構刪改增添一下,如有思路上的雷同十分正常。
「是時候開啟fft的大門了!」
1.至少知道基礎數論與一定解三角形知識(大概是高中水平)。
2.定義\(i=\sqrt\)
3.引入複數(即形如\(a+bi\)(a,b均為實數)的數的集合)
4.\((cos\theta+i\times sin\theta)^k=cos(k\theta)+i\times sin(k\theta)\)
5.顯然我們對多項式fft之後得到的答案不是我們想要的,那麼這時候就需要反著用fft把式子再變回去(本文記做ifft)。
這裡證明一下第四條,用歸納法。顯然當\(k=1\)時成立。
當\(k\)成立時,我們有:
\((cos\theta+i\times sin\theta)^\)
\(=(cos\theta+i\times sin\theta)^k\times (cos\theta+i\times sin\theta)\)
\(=(cos(k\theta)+i\times sin(k\theta))\times (cos\theta+i\times sin\theta)\)
\(=cos(k\theta)cos\theta+i\times sin(k\theta)cos\theta+i\times cos(k\theta)sin\theta+i^2\times sin(k\theta) sin\theta\)
\(=cos(k\theta)cos\theta-sin(k\theta) sin\theta+i\times (sin(k\theta)cos\theta+cos(k\theta)sin\theta)\)
\(=cos((k+1)\theta)+i\times sin((k+1)\theta)\)
得證。
設\(a(x)=\sum_^a_ix^i,b(x)=\sum_^b_ix^i\),求\(a(x)\times b(x)\)後的多項式係數。顯然我們有乙個\(o(n^2)\)的解法,但是實在是太慢了。
考慮到乙個\(n-1\)次多項式可以看做是定義在複數域上的函式,則我們一定可以找到n個點來唯一確定這個函式。
當然我們也可以通過這些點來表示這個多項式。
假設:\(a(x)\)被表示為:\(<(x_0,y_),(x_1,y_),\ldots,(x_,y_})>\)
\(b(x)\)被表示為:\(<(x_0,y_),(x_1,y_),\ldots,(x_,y_})>\)
顯然\(a(x)\times b(x)\)被表示為:\(<(x_0,y_y_),(x_1,y_y_),\ldots,(x_,y_}y_})>\)
這裡多取了點的原因在於\(a(x)\times b(x)\)是乙個\(2n-2\)次多項式,則至少要取\(2n-1\)個點才能保證正確。但是顯然還是\(o(n^2)\)的。
考慮設\(a(x_i)=a_0(x_i^2)+x_ia_1(x_i^2)\),其中:
\(a_0(x)=a_0+a_2x+a_4x^2+\ldots+a_x^+1}\)
\(a_1(x)=a_1+a_3x+a_5x^2+\ldots+a_x^+1}\)
其實就是按照係數下標的奇偶性分類了一下。此時我們再令取點的\(x\)值為\(\)
我們發現把\(x\)平方後我們的取值瞬間縮小了一半,而原式唯一變化的就是\(a_1(x)\)前的符號。
看起來我們似乎找到了\(o(nlogn)\)的可行方案。
但是很可惜,這樣優秀的\(x\)取值的性質只會保留一次,也就是說我們只是得到了乙個\(o(\frac)\)。
如何才能每次將問題的規模縮小一半是我們的目標。
有個人告訴你:不如試試\(x_n=cos\frac+i\times sin\frac\) 的 \(0\ldots n-1\)次方作為\(x\)的取值。
這塊大家一直有個疑惑:這是怎麼構造出來的啊?那麼令取點的\(x\)值為\(\)事實上傅利葉變換最早是應用於訊號處理上的,傅利葉提出:任何連續週期訊號可以由一組適當的正弦曲線組合而成。
多項式可以看做非連續週期訊號,然後通過各種奇妙的姿勢讓它逼近正弦曲線的組合形,詳情可以看鬆鬆松wc2018的課件。
「逼近」顯然用到了微積分,不適合初學者,所以就直接跳過了。(其實我也不會……)
(再多說一點吧,其實上面和下面的數學推理完全可以從物理層面理解,還是可以參考鬆鬆松wc2018的課件)
我們可知:
\((x_n^)^2\)
\(=x_n^\)
\(=cos\frac+i\times sin\frac\)
\(=cos\frac}+i\times sin\frac}\)
\(=x_}^k\)
\(x_n^\)
\(=cos\frac+i\times sin\frac\)
根據三角函式的週期性可知,\(k\)對\(n\)取模顯然不會對答案造成影響。
於是我們有\(x_n^=x_n^\)
那麼顯然對於\(<(x_n^0)^2,(x_n^1)^2,\ldots,(x_n^)^2>\)
它等效於\(\)
我們好像看到了\(o(nlogn)\)的曙光了。
顯然我們可以對\(x\)的取值折半,然後對於左右區間的\(x\)值遞迴下去即可。
q1:誒等等,「再試」裡面的內容好像沒有應用上啊……
a1:那就轉化一下,其實我們只需要求乙個區間的\(a_0(x)\)和\(a_1(x)\)值遞迴下去求\(a(x)\)即可。
也就是說其實我們是得到了:
\(<(a_0)_0,(a_0)_1,\ldots,(a_0)_-1},(a_1)_0,(a_1)_1,\ldots,(a_1)_-1}>\)
q2:這好像是畫蛇添足……
a2:emmm……我說這個可以用於常數優化你信嗎……
顯然\(a(x_n^k)=(a_0)_}+x_n^k(a_1)_}\)
取模是因為,不要忘了我們的取值是由兩個一樣的左右區間合併在一起的。那麼我們得到了\(\)
(其中\(a_k=a(x_n^k)\))
我們好像把這個序列的長度減少了一半誒!那自然是快了二倍啊。
不要忘了n要滿足始終是2的倍數,所以n要取2的整數次冪,同時將沒用的次冪的係數填成0。q3:ifft怎麼做啊?
a3:繼續看下去……?
略講一下ifft。
顯然我們可以把fft的最初演算法(也就是dft)看做兩個矩陣相乘。
兩個矩陣分別乙個填\((x_n^k)^m\),乙個填係數,可以上參考處原部落格看矩陣。那麼我們把第乙個矩陣變成逆矩陣豈不是為ifft?
其實就是這樣,並且事實上就是填\(((x_n^)^m)/n\),具體證明過程看參考處原部落格。
剩下的做法就和fft一樣啦。
事實上我上述講的內容其實沒有多少用(滑稽。
因為你理解半天也不如不理解知道怎麼用然後默寫下來。
但是理解了更好背啊。
模板:hdu1402:a * b problem plus:
應用:bzoj3527:[zjoi2014]力:
+++++++++++++++++++++++++++++++++++++++++++
快速傅利葉變換FFT
fft的作用就不多說了,搞訊號處理的人都會用上。fft的由來 傅利葉變換ft 離散傅利葉變換dft 快速傅利葉變換fft。學習資料 1 陳後金的 數字訊號處理 裡面深入淺出,該有的公式都有,程式設計思想也有。2 一篇系統講述傅利葉變換的帖子 3 學生對fft的理解 4 工程人員對fft的簡單明瞭的總...
快速傅利葉變換 FFT
bzoj 2179 fft快速傅利葉 果題 bzoj2194 請計算c k sigma a i b i k 其中 k i n 並且有 n 10 5。a,b中的元素均為小於等於100的非負整數。注意到i 和 i k有奇妙的聯絡 不妨嘗試把b翻轉 然後就變成卷積了。貼個模板 include define...
快速傅利葉變換 FFT
首先說一下我用fft做什麼,我要做的是多項式乘法,或者說,加速多項式乘法。考慮多項式a x j 0n 1aj xj,它一共有 n 項,我們稱它的次數界為 n。假設我們有兩個次數界為 n 的多項式a x 和b x 要求它們的和是非常簡單的,只需要將對應的係數相加,複雜度為o n 如果要求他們的積,則需...