fft,即快速傅利葉變換,是將多項式乘法從 \(o(n^2)\) 優化到 \(o(n\log n)\) 的演算法。
本質上是優化卷積,卷積的一般形式:
\[c(i)=\sum\limits_a(i)b(i)
\]其中多項式乘法為加法卷積,即:
\[c(i)=\sum\limits_a(i)b(i)
\]我們可以用每個項的係數來表示這個多項式:
\[f(x)=a_nx^n+\dots +a_2x^2+a_1x+a_0\rightarrow f(x) = \
\]我們可以把多項式看成乙個函式,那麼從平面上取 \(n+1\) 個點,則可以確定乙個 \(n+1\) 項的函式。
原因可以理解成 \(n+1\) 個多項式,也就是 \(n+1\) 個方程,可以解出 \(n+1\) 元的方程。
fft 的原理就是將對於每乙個多項式 \(a(x)\) 和 \(b(x)\) 由係數表示法變成點值表示法,\(a(x)\) 和 \(b(x)\) 相乘得 \(c(x)\) ,再變成係數表示法。將係數表示法變成點值表示法的過程稱為 dft,點值表示法變成係數表示法的過程稱為 idft。
但如果暴力算的話,\(a(x)\) 和 \(b(x)\) 變成點值表示法是 \(o(n^2)\) 的,再用高斯消元求解是 \(o(n^3)\) ,所以 fft 可以加速這個過程。
對於點值表示法的 \(n\) 個 \(a(x)\) 和 \(b(x)\) ,需要快速算出它們的值。
直接算 \(o(n^2)\) 的,發現對於 \(x^n=1\) 的 \(x\) ,可以 \(o(n)\) 計算出 \(a(x)\) 和 \(b(x)\) 。
在實數域中,只有 \(1\) 和 \(-1\) 滿足 \(o(n)\) 算出多項式。
在複數域中,則有 \(i\) 和 \(-i\) 滿足要求。
考慮複數乘法,表示為模長相乘,輻角相加,則兩個模長為 \(1\) 的向量相乘,得到的還是模長為 \(1\) 的向量。
可以定義 \(x^n=1\) 在複數意義下的解為 \(n\) 次復根,即 \(\omega_\) 。這樣的復根有 \(n\) 個,表示為 \(\omega_^k\) ,其中 \(k=0,1,\dots,n-1\)
oi-wiki上的圖:
性質:\[\omega_^k=\omega_^
\\\omega_^=-\omega_^k
\]fft 的基本思想是分治。
我們將多項式分為奇次項和偶次項處理。
對於乙個 \(8\) 項多項式,按照次數分為兩組:
\[f(x)=(a_0+a_2x^2+a_4x^4+a_6x^6)+(a_1x+a_3x^3+a_5x^5+a_7x^7)\\=(a_0+a_2x^2+a_4x^4+a_6x^6)+x(a_1+a_3x^2+a_5x^4+a_7x^6)
\]\[g(x)=a_0+a_2x+a_4x^2+a_6x^3\\
h(x)=a_1+a_3x+a_5x^2+a_7x^3
\]則有:
\[f(x)=g(x^2)+x\times h(x)
\]\[\begin\operatorname(f(\omega_n^k))&=\operatorname(g((\omega_n^k)^2))+\omega_n^k\times \operatorname(h((\omega_n^k)^2))\\ &=\operatorname(g(\omega_n^)) + \omega_n^k\times \operatorname(h(\omega_n^))\\ &=\operatorname(g(\omega_^k)) + \omega_n^k \times \operatorname(h(\omega_^k))\end
\]同理可得:
\[\begin\operatorname(f(\omega_n^))&=\operatorname(g(\omega_n^))+\omega_n^\times \operatorname(h(\omega_n^))\\&=\operatorname(g(\omega_n^))-\omega_n^k\times \operatorname(h(\omega_n^))\\&=\operatorname(g(\omega_^k))-\omega_n^k\times \operatorname(h(\omega_^k))\end
\]所以我們可以對 \(g\) 和 \(h\) 分別遞迴求解,得出 \(\operatorname(f(\omega_^))\) 和 \(\operatorname(f(\omega_^))\)
dft 很明顯可以用遞迴求解,但它還可以繼續優化。
考慮到遞迴的過程是不斷對若干個長為 \(2^m\) 的子段拆分成兩個長為 \(2^\) 的子段,並且每次遞迴 \(m-1\) 直到 \(m=1\) ,那麼可以考慮從 \(m=1\) 的狀態開始合併。
容易發現每個數在拆分到 \(m=1\) 時的位置和原始位置的二進位制是翻轉的,那麼求出rev[i]
表示 \(i\) 的二進位制反轉後的值即可。
這裡給出**:
code-rev
for (int i = 0; i < len; ++i)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (num - 1));
idft 相當於已知 \(y_i=f(\omega_^i)\) ,\(i\in\\) ,求 \(\\}\)
我們取單位根的倒數,跑一邊 fft,再將求得的 \(y\) 除以 \(n\) ,得到原來的 \(a\) 。
證明:設 \(b_i=\omega_^,i\in \,y_i=f(\omega_^i)\)
\[a(b_k)=\sum\limits_^f(\omega_^i)\omega_^\\
=\sum\limits_^\omega_^\sum\limits_^a_j\omega_^\\
=\sum\limits_^\sum\limits_^a_j\omega_^\\
=\sum\limits_^a_j\sum\limits_^(\omega_^)^i\\
=a_k\times n
\]得證。
code-fft
void fft(fu *y, int on) ;
for (int j = 0; j < len; j += h) ;
for (int k = j; k < j + h / 2; ++k)
}} if (on == -1)
for (int i = 0; i < len; ++i)
y[i].x /= len;
}
模板題,給出**。
code
#include #define ll long long
#define ull unsigned long long
#define db double
#define pr pair #define mk make_pair
#define pb push_back
#define fi first
#define se second
#define ri register int
#define low(x) (x & (-x))
using namespace std;
const int kn = 4e6 + 5;
const db pi = acos(-1.0);
int n, m, len = 1, num = 0, rev[kn];
struct fu ;}
fu operator - (const fu &k) const ;}
fu operator * (const fu &k) const ;}
} f[kn], g[kn];
void fft(fu *y, int on) ;
for (int j = 0; j < len; j += h) ;
for (int k = j; k < j + h / 2; ++k)
}} if (on == -1)
for (int i = 0; i < len; ++i)
y[i].x /= len;
}signed main()
fft 是用來優化多項式乘法,也就是加法卷積,在多項式方面可以被 ntt 所取代,因為 ntt 可以取模,其實 fft 和 ntt 只是從 \(\omega\) 換成原根罷了,沒什麼區別。 關於福利院人員定位管理的系統介紹 新導智慧型
每個孩子都是祖國的花朵,他們的健康成長是我們的責任.尤其是福利院的孩子,他們被遺棄,孩子的心理已經造成了創傷,此時,孩子們的心理及身體的健康,我們必須實時監控.這樣我們就可以對孩子們進行實時監控,隨時隨地的了解孩子們的生命體徵的各項資料.例如,孩子的血壓,心跳等等.甚至還可以使用尿濕監測系統.對孩子...
精美jQuery外掛程式及原始碼 前端開發福利
這是一款基於jquery的自定義下拉框選擇列表外掛程式,利用這款jquery外掛程式我們可以非常方便的讓瀏覽器預設的select下拉框變的非常華麗,並且同時擁有select下拉框原有的功能。這款jquery下拉框外掛程式利用了css3技術,提供了5款不同的炫酷樣式。今天我們要來分享一款基於html5...
玉樹一所福利院震後聳立不倒 105名兒童未受傷
帳篷福利院 孩子的笑臉 本報特派記者 王穎 攝 震前的玉樹州懷德兒童福利院 震前的玉樹州懷德兒童福利院 在玉樹災區,最牽動人心的,莫過於孩子的 而最打動人心的,莫過於孩子的笑臉。昨天,玉樹震中結古鎮災區,我們看到孤兒們的臉上綻放出了笑容。孩子乙個沒傷著 帳篷福利院冒出裊裊炊煙 昨天下午6點,玉樹跑馬...