複數
重要性質:複數相乘,輻角相加,模長相乘。
即 \(\operatorname(z_1\times z_2)=\operatorname(z_1)+\operatorname(z_2)\)。
那麼 \(\operatorname(z^n)=n\operatorname(z)\)。
弧度制三角函式
\(n\) 次冪 為 \(1\) 的複數叫做 \(n\) 次單位根,即方程 \(z^n=1\) 的複數根。\(n\) 次單位根有 \(n\) 個。
因為 \(z^n=1\),所以 \(\left\vert z\right\vert^n=1\)。而模長一定是個非負實數,所以 \(\left\vert z\right\vert=1\)。也就是說單位根到原點的距離為 \(1\),一定在單位圓(以原點為圓心,半徑為 \(1\) 單位長度的圓)上。
我們把所有 \(n\) 次單位根從 \(1\) 開始,沿逆時針方向記為 \(\omega_n^0,\omega_n^1,\dots\omega_n^\)。
由原方程還可以得到 \(\operatorname((\omega_n^k)^n)=n\operatorname(\omega_n^k)=\operatorname(1)\),所以把 \(1\) 逆時針旋轉 \(n\) 次,每次旋轉 \(\operatorname(\omega_n^k)\),結果還是 \(1\)。那麼 \(2\pi\mid n\operatorname(\omega_n^k)\)。每個單位根又互不相同,所以 \(\operatorname(\omega_n^k)=\dfrac2\pi\)。它們把單位圓 \(n\) 等分。\(\omega_n^k\) 相當於繞原點把 \(\omega_n^\) 逆時針旋轉 \(\dfrac\)。
對於 \(k~(k\ge n)\),定義 \(\omega_n^k=\omega_n^\)
性質:\(\omega_n^k=(\omega_n^1)^k\)
\(\omega_^=\omega_n^k\)
因為它們模長都是 \(1\),輻角也相等。
\(\omega_n^i\times\omega_n^j=\omega_n^\)
用性質 1 容易得證。
若 \(n\) 是偶數,\(\omega_n^}=-\omega_n^k\)
\(\omega_n^}=\omega_n^k\times\omega_n^\frac\),\(\operatorname(\omega_n^\frac)=180^\circ\),相當於把 \(\omega_n^k\) 繞原點旋轉 \(180^\circ\),即關於原點中心對稱,實部虛部都取相反數,所以是 \(-\omega_n^k\)。
\(\sum\limits_^\omega_n^i=\dfrac\times\omega_n^1-\omega_n^0}=0\)
(等比數列求和)
\(n+1\) 個點確定唯一 \(n\) 次多項式。我們可以用 \(n+1\) 個點表示原多項式,並對點值序列進行一些操作(如乘法),最後由這個點值序列得到乙個新的多項式,來代替原多項式之間的操作。
比如 \(f(x)=x^2+2x-1,g(x)=-3x+1\)
在 \(f(x)\) 上取 \((-1,-2)(0,-1)(1,2)(2,7)\)
在 \(g(x)\) 上取 \((-1,4)(0,1)(1,-2)(2,-5)\)
兩個點值序列中,橫座標相同的點的縱座標相乘,得到 \((-1,-8)(0,-1)(1,-4)(2,-35)\)
根據這些點確定乙個 \(3\) 次多項式得到 \(-3x^3-5x^2+5x-1\),恰好等於 \(f(x)\cdot g(x)\)。
dft 是把係數表達轉換成點值表達的過程。我們把單位根代入多項式得到點值序列。
考慮乙個 \(n-1\) 次(\(n\) 項)多項式 \(f(x)=\sum\limits_^f_ix^i\)。
由於 \(n\) 是 \(2\) 的整數冪時比較好做,故 \(n\) 不是 \(2\) 的整數冪時往高次項補 \(0\)。
把它按次數的奇偶性分類:
\(f(x)=f_0+f_2x^2+\dots+f_x^+f_1x+f_3x^3+\dots+f_x^\)
令 \(fl(x)=f_0+f_2x+f_4x^2+\dots+f_x^,fr(x)=f_1+f_3x+f_5x^2+\dots+f_x^\)
則有 \(f(x)=fl(x^2)+xfr(x^2)\)。
現要把單位根代入 \(f\)。
列舉 \(k~(0\le k<\dfrac)\)
\(f(\omega_n^k)=fl((\omega_n^k)^2)+\omega_n^kfr((\omega_n^k)^2)=fl(\omega_^k)+\omega_n^kfr(\omega_^k)\)
\(f(\omega_n^)=fl((\omega_n^)^2)+\omega_n^fr((\omega_n^)^2)=fl(\omega_n^)+\omega_n^fr(\omega_n^)=fl(\omega_^k)-\omega_n^kfr(\omega_^k)\)
如果我們知道了 \(x=\omega_^k~(0\le k時 \(fl(x)\) 和 \(fr(x)\) 的值,就可以算出 \(x=\omega_n^k~(0\le k時 \(f(x)\) 的值。\(fl,fr\) 可以遞迴求。
求單位根:用三角函式求出 \(\omega_n^1\),利用性質 1 每次乘上它,防止多次呼叫三角函式。
\(\large\\\large^k)+\omega_n^kfr(\omega_^k)}\\\large)=fl(\omega_^k)-\omega_n^kfr(\omega_^k)}\)
有了點值序列還不夠,我們還得根據點值求多項式。
令 \(g\) 為點值序列即 \(g_k=f(\omega_n^k)=\sum\limits_^f_i(\omega_n^k)^i\)
有 \(nf_k=\sum\limits_^(\omega_n^)^ig_i\)
也就是說,對 \(g\) 再做一遍 dft,不同的是初始單位根為 \(1\),每次乘上 \(\omega_n^\)
而 \(\omega_n^\) 是 \(\omega_n^\) 的共軛。
不會證根據上文可以寫出遞迴的版本,但常數較大。現在嘗試寫出非遞迴版。
考慮 \(0\dots n-1\) 次項係數遞迴到每一層時的位置。
以 \(n=8\) 為例
0 1 2 3 4 5 6 7
---------------
0 1 2 3 4 5 6 7
0 2 4 6|1 3 5 7
0 4|2 6|1 5|3 7
0|4|2|6|1|5|3|7
寫出第一行和最後一行的二進位制
| | 原 | 現 |
| 0 | 000 | 000 |
| 1 | 001 | 100 |
| 2 | 010 | 010 |
| 3 | 011 | 110 |
| 4 | 100 | 001 |
| 5 | 101 | 101 |
| 6 | 110 | 011 |
| 7 | 111 | 111 |
我們發現,最後一行 \(i\) 位置上的數其實是位數為 \(\log n\) 時 \(i\) 在二進位制下反轉得到的數。 於是可以預處理出 \(i\) 在二進位制下反轉得到的數,也就能得到最後一行。此時他們都是 \(0\) 次,可以直接當做單位根代入得到的值。
然後列舉現在要處理 \(m\) 次多項式(\(m=2,4,8,.\dots,n\))。把序列分成 \(\dfrac\) 段,列舉段的起始點 \(l\),在這一段內列舉 \(k~(0\le k<\dfrac)\) 計算 \(f(l+k)\) 和 \(f(l+\dfrac+k)\).
**(多項式乘法):
const double pi = acos(-1);
int tr[n], n, m;
struct cp
inline cp operator - (const cp &c) const
inline cp operator * (const cp &c) const
cp() {}
cp(const double &_x, const double &_y) : x(_x), y(_y) {}
} f[n], g[n];
inline void swap(cp &x, cp &y)
void fft(cp *f, int fl)
} }}signed main()
FFT學習筆記
fft可用於解決一些卷積問題。一般問題形式如下 c a b c i ij 0a i b i j 若把a,b看成兩個次數為n多項式 a x ni 0 a i xi,b x ni 0b i x i 原問題等於兩個多項式相乘,c的次數等於2n 1 乙個次數界為n的多項式a的點值表達為n個點值對所組成的集合...
FFT學習筆記
今天doggu講了,開始覺得這玩意好強啊 後來自己看的時候發現蠻zz wys表示 贊同 所以很多自己覺得遙不可及,一輩子都不可能學會的東西只要慢慢理解,理解好了再把他化為自己的語言,歸到自己的世界裡 就覺得不是很難了,甚至很簡單.當然開始並不是,從 好難啊 到 這麼簡單困大爺我這麼久,之前腦子抽了z...
FFT 學習筆記
f x sum limits a i x i x 0,f x 0 x 1,f x 1 x f x 首先我們要了解複數 即 i sqrt 乙個數有實部和虛部 即 a x y i x,y 原來的實數運算相當於在乙個一維數軸上進行移動,複數則是在二維平面上運動 一句話來說就是摸長相乘,幅角相加 c 中提供...