去北京學習的時候才系統的學習了一下卷積,當時整理了這個筆記的大部分。後來就一直放著忘了寫完。直到今天都臘月二十八了,才想起來還有個fft的筆記沒整完呢。整理完這個我就假裝今年的任務全都over了吧。
更改了一些以前不大正確的地方,又新增了一些推導,證明實在不會。
有一些公式,但個人覺得還是比較好理解。可能還會有錯誤,希望大佬友情指出。
最後,祝各位看官新年快樂.
回家過寒假去咯(雖然就\(4\)天\(qwq\))
乙個次數界為\(n\)的多項式\(a(x) = \sum_^a_ix^i\)
次數界為\(n\)說明這個多項式最高次項的指數小於\(n\)
我們可以只保留多項式每項的係數來描述這個多項式。即\(a_i\)表示指數為\(i\)的項的係數
多項式之間的加運算,只要將對應項的係數相加即可。
即若\(c(x) = a(x) + b(x)\)那麼有\(c(x) = \sum_^\)
多項式之間的乘法。
若\(c(x) = a(x) + b(x)\)那麼\(c(x) = \sum_^^ia_jb_x^i}\)
其中\(c(x) = \sum_^^ia_jb_x^i}\)叫做卷積
可以看出暴力計算卷積的複雜度為\(o(n^2)\)
我們可以選\(n\)個值代入多項式從而得出\(n\)個二元組\((x_i,y_i)\)。可以證明,通過這\(n\)個點對可以確定這個多項式。
還原這個多項式用高斯消元即可。
點值表示法的優點是進行多項式的加法和乘法只要將\(y_i\)相加或者相乘即可。
考慮如何可以比較快速的計算卷積。因為點值表示計算乘法比較方便。所以我們可以把係數表示法轉換為點值表示法。然後進行乘法。然後在轉換回來。就可以計算卷積了。
把係數表示法轉化為點值表示法稱為求值,把點值表示法轉換為係數表示法稱為插值。
\(a(x) = \sum_^y_i\frac}}\)
利用拉格朗日插值公式可以在給定\(n\)個點值表示法的情況下\(o(n^2)\)時間內計算出原二項式在某個位置的值
離散傅利葉變換實現了兩種表示法之間的轉換,複雜度是\(o(n^2)\)
複數是形如\(a+bi\)的數,其中\(a,b\)為實數。\(a\)稱為實部,\(b\)稱為虛部。\(i\)為虛數單位,定義\(i^2 = -1\)
複數是數的範圍在實數上的擴充套件
將複數\(a+bi\)表示在數軸上,是乙個\((a,b)\)的向量.
複數相加將\(a\)和\(b\)分別相加即可。
複數相乘,其實將i看作未知量相乘就行了。即\((a+bi)*(x+yi) = (ax - by) + (ay + bx)i\)
在數軸上以原點為圓心半徑為\(1\)的圓。
\(n\)次單位根滿足\(\omega^n = 1\)。\(\omega 就是n次單位根\)
表現在單位圓上就是單位圓的\(n\)等分點
我們用\(\omega_n\)表示主\(n\)次單位根也就是從\((1,0)\)開始數第乙個n次單位根
那麼可以得到其他的\(n\)次單位根分別為\(\omega_n^0,\omega_n^2,\omega_n^3,.....\omega_n^\)
性質:\(\omega_n^n = 1\)當n為偶數時,\(\omega_n^ = -1\)
\(\sum_^\omega_n^i=0\)
\(e^ = cos(x)+i * sin(x)\)
\(\omega_n=e^ = cos(\frac)+i*sin(\frac)\)
用來求主\(n\)次單位根
有了上面這些鋪墊,就可以進行轉換了。
將\(n\)個\(n\)次單位根帶入原來的多項式,就可以得到\(n\)個點值表示法。
那麼怎麼將點值表示法轉換為係數表示法呢?
這就是用\(n\)次單位根的原因
我們將得到\(n\)個\(y\)作為另乙個多項式\(b(x)\)的係數
然後取單位根倒數帶入就能得到原來的多項式\(a(x)\)啦
這樣就成功的實現了點值表示法與係數表示法之間的轉換
用\(dft\)計算卷積的複雜度是\(o(n^2)\)的。利用快速傅利葉變換可以優化到\(o(nlogn)\)
考慮乙個次數界為\(n\)的多項式\(a(x)\)求他的\(dft\)
這裡預設\(n\)為偶數,如果\(n\)不是偶數,那麼只要加上乙個係數為\(0\)的項即可將他填充為偶數
然後我們根據下標的奇偶性將他分為兩部分。
\[a_(x) = a_0 + a_2x + a_4x^2....+ a_x^ - 1}
\]\[a_(x) = a_1 + a_3x+a_4x^2....+a_x^-1}
\]然後就能得到\(a(x)=a_(x^2) + xa_(x^2)\)
然後發現\(a_(x)\)和\(a_(x)\)是可以用同樣的方法遞迴計算的。所以就可以進行分治然後遞迴運算。
那麼我們需要帶入這\(n\)個單位根,應該怎麼計算呢。
下面進行推導
假如現在要把\(\omega_^i\)代入
依據上面的式子
\[a(\omega_n^i)=a(\omega_n^) + \omega_n^a(\omega_n^)
\]\[=a(\omega_}^i)+\omega_n^ia(\omega_}^i)
\]然後考慮\(a(\omega_n^})\)
\[a(\omega_n^}) = a(\omega_^) + \omega_n^} a(\omega_^)
\]\[=a(\omega_^\omega_n^n) + \omega_n^ \omega_^} a(\omega_^\omega_n^n)
\]\[=a(\omega_}^i) - \omega_n^a(\omega_}^i)
\]然後就可以遞迴的愉快的計算出將這\(n\)個單位根代入所得到的值
遞迴實現\(fft\)非常慢。所以要用非遞迴的方法來實現
我們將遞迴實現的過程寫下來
0 1 2 3 4 5
0 2 4|1 3 5
0 4|2|1 5|3
0|4|2|1|5|3
然後看出每個數字遞迴到最後的為是為當前位置二進位制表示法翻轉之後的數字。
然後就可以先把每個數字都放到最後的位置上面,然後再合併就行了。
/*
* @author: wxyww
* @date: 2019-02-01 21:09:51
* @last modified time: 2019-02-01 21:47:34
*/#include#include#include#include#include#include#includeusing namespace std;
typedef long long ll;
const int n = 3000100;
const double pi = acos(-1.0);
ll read()
while(c>='0'&&c<='9')
return x*f;
}struct complex
complex(double xx,double yy)
}a[n],b[n];
complex operator * (complex a,complex b)
complex operator + (complex a,complex b)
complex operator - (complex a,complex b)
void fft(complex *a,int n,int ty)
fft(a1,n >> 1,ty);fft(a2,n >> 1,ty);//遞迴
complex w1 = complex(cos(2.0 * pi / n),ty * sin(2.0 * pi / n));//主n次單位根
complex w = complex(1.0,0.0);//當前的n次單位根
int k = n >> 1;
for(int i = 0;i < k;++i)
}int main()
/*
* @author: wxyww
* @date: 2019-02-01 21:50:51
* @last modified time: 2019-02-01 22:03:10
*/#include#include#include#include#include#include#includeusing namespace std;
typedef long long ll;
const int n = 3000100;
const double pi = acos(-1.0);
ll read()
while(c>='0'&&c<='9')
return x*f;
}struct complex
complex(double xx,double yy)
}a[n],b[n];
complex operator * (complex a,complex b)
complex operator + (complex a,complex b)
complex operator - (complex a,complex b)
void fft(complex *a,int n,int ty)
for(int m = 2;m <= n;m <<= 1)
} }}int main()
最後來乙份遞迴**與非遞迴**執行時間的比較 快速傅利葉變換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 如果要求他們的積,則需...