簡單的乘法公式蘊含排列組合的意義
定義一個數列 \(\langle a_n \rangle\)的一般生成函數如下
(又稱形式幂級數、組合生成函數)
順便定義 \(x^k\) 的係數是 \(F[x^k] = a_k\)
\(a_n \in F\)
聽說 F 要是一個 Field
還有這邊先不要管 x 收不收斂
加法減法應該不用解釋吧@@
可以想成 \(a_n\) 就代表「拿 \(n\) 個的方法數」
那如果現在有兩種物品,拿 \(n\) 個的方法數分別是 \(a_n, b_n\)
那麼我們把他們乘在一起得到的多項式就代表總共拿了 \(n\)個的方法數
m(_ _)m
費式數列?
\[a_0=0, a_1=1, a_n=a_{n-1}+a_{n-2}\]
卡特蘭數
不同構的n個節點二元樹的數量
咦?我不會除法QQ
其中 \(\alpha, \beta\)是分母的兩個根
review: \(\cfrac{1}{1-rx} = \sum\limits_{k=0}^\infty{r^kx^k}\)
所以 \(F[x^n] = A\alpha^n + B\beta^n\)
微積分!
「惟天下之靜者乃能見微而知著。」
若\(f(x)\)(\(f\))為一個函數,則將\(f\)的微分寫作\(f'\)。
微分代表
一個函數的斜率
(notation) \(\frac{\text{d}f}{\text{d}x}\) 為
「若變化\(x\)的值一點點,那\(f\)會變化多少?」
(單項式微分)
(連鎖律)
(乘法)
(加法)
Note: \(f\circ g = f(g)\)
若\( a_i = i\),請找出\(\langle a_i\rangle\)的生成函數?
所以\(\frac{1}{(1 - x)^2}\)即為所求!
若\( a_i = i^2\),請找出\(\langle a_i\rangle\)的生成函數?
但是 還不夠耶
若\( a_i = i^2\),請找出\(\langle a_i\rangle\)的生成函數?
只是需要一點巧思嘛!
「積土成山,風雨興焉;積水成淵,蛟龍生焉;積而算之,題AC焉」
若\(f\)為一個函數,則將\(f\)的積分寫作\(\int f\)。
積分代表
一個函數地下的面積
(單項式微分)
(分布積分)
(加法)
積分和微分互為反運算!
\(O(n)\) (trivial)
Point-Value representation
Coefficient representation
\((a, f(a)), (b, f(b)), \dots (jizz, f(jizz))\)
\( f(x) = \sum a_kx^k\)
運算簡單
運算不簡單
推 >< by Sean
Point-Value representation
Coefficient representation
乃衣服:\(O(n^2)\)
FFT:\(O(n \log n)\)
Definitions & Basic Properties
讀:\(n\)次原根的\(k\)次方
Problem Statement
現在,給定一個函數\(f(x) = \sum\limits_{k=0}^{n-1} a_k x^k\),請求\((1, f(1)), (\omega_n, f(\omega_n), (\omega_n^2, f(\omega_n^2)) \dots (\omega_n^{n - 1}, f(\omega_n^{n - 1})\)?
矩陣表示法
以後,我們將假設\(n\)為\(2\)的冪次。若不是,則可以補零到是就好了。
TL;DR:\(n = 2^l\)
\(n \log n\) Speedup
\(f(x) = E(x^2) + xO(x^2)\)
假設\(O(x) = \sum_{k =0} a_{2k+1}x^k\),\(E(x) = \sum_{k =0} a_{2k}x^k\)
\(n \log n\) Speedup
\(f(x) = E(x^2) + xO(x^2)\)
若\(O[k] = O(\omega_{\frac{n}{2}}^{k})\),\(E[k] = E(\omega_{\frac{n}{2}}^{k})\),所求\(f[k] = f(\omega_n^k)\)
遞迴計算的結果
\(n \log n\) Speedup
\(n \log n\) Speedup
And then...
但是...
有了這堆東西...
除了炫耀還能幹嘛啊?
感覺還需要一個東西轉回去⋯⋯
Inverse FFT
還記得FFT有矩陣表示方式嗎:\(A_{ij} = \omega_n^{ij}\) (0 base)
那可以證明,\((A^{-1})_{ij} = \frac{\omega_n^{-ij}}{n}\)哦!
(\(i\neq j\)的時候是和為0的等比級數)
const double PI = acos(-1);
typedef complex<double> cd;
vector<cd> FFT(const vector<cd> &F, bool inv) { // assume F.size() == 2^k
if(F.size() == 1) return F; // base case (important)
vector<cd> rec[2];
for(int i = 0; i < F.size(); i++) rec[i&1].push_back(F[i]);
rec[0] = FFT(rec[0],inv);
rec[1] = FFT(rec[1],inv);
double theta = (inv ? 1 : -1) * 2 * PI / F.size();
cd now = 1, omega(cos(theta), sin(theta));
vector<cd> ans(F.size());
for(int i = 0; i < F.size()/2; i++) {
ans[i] = rec[0][i] + now * rec[1][i];
ans[i+F.size()/2] = rec[0][i] - now * rec[1][i];
now *= omega;
}
if(inv) for(int i = 0; i < ans.size(); i++) ans[i] /= 2;
return ans;
}
註:為求效率,也可以寫成迴圈版本,避免遞迴
const double PI = acos(-1);
typedef complex<double> cd;
void FFT(cd F[], int n, bool inv) { // in-place FFT, also assume n = 2^k
for(int i = 0, j = 0; i < n; i++) {
if(i < j) swap(F[i], F[j]);
// magic! (maintain j to be the bit reverse of i)
for(int k = n>>1; (j^=k) < k; k>>=1);
}
for(int step = 1; step < n; step <<= 1) {
double theta = (inv ? 1 : -1) * PI / step;
cd omega(cos(theta), sin(theta));
for(int i = 0; i < n; i += step*2) {
cd now(1,0);
for(int j = 0; j < step; j++) {
cd a = F[i+j];
cd b = F[i+j+step] * now;
F[i+j] = a+b;
F[i+j+step] = a-b;
now *= omega;
}
}
}
if(inv) for(int i = 0; i < n; i++) F[i] /= n;
}
Implement an operation that is equivalent to the operation \(DFT^P\), where \(DFT\) is the discrete Fourier transform.
一種方法是先取ln,乘上倍數後再exp
另一種方法則是
牛頓逼近法
結論:
\(A(x) = B(x)Q(x) + R(x)\)
設\(n = \deg A \geq m = \deg B\)
則\(\deg Q = n-m, \deg R < m\)
當你想要考慮物件的順序的時候可以考慮「指數生成函數」
光維基上神奇的生成函數就好多 OAO
例如什麼跟數論函數有關的Lambert、Dirichlet之類的
理論上只要保證解析函數 \(\mu_k(x)\)線性獨立
\(\sum_{k=0}^\infty a_k \mu_k(x)\) 應該都可以拿來用吧(?)
例如 \(\mu_k(x) = \cos(kx)\) 之類的
以上言論若有錯誤不負責
取數個物品A和物品B,共取n個
排列順序不同算不同方式的方法數
可以知道題目就是要求有兩個環的排列
我們先考慮恰是一個環的排列,有 \((n-1)!\) 種方法數
那麼從 \(n\) 個元素裡面選出 \(k\) 個分給第一個環,另外 \(n-k\)個分給第二個環,也就是
\[\sum_k \binom{n}{k}(k-1)! (n-k-1)!\]
令 \(\displaystyle F = \sum_{k=0}^n (k-1)! \frac{x^k}{k!}\)
所求就是 \(\frac{1}{2}F^2\)
連講師都不會