尤拉函式
定義
公式
對於所有質數,顯然有 \(\phi(n) = n - 1\)。
對於 \(n = p_1^{a_1}p_2^{a_2}\cdots p_k^{a_k}\),
證明
- 如何求 \(p_i \mid x\) 的個數?\(\lfloor \dfrac{n}{p_i} \rfloor\)。
- 是否 \(\phi(n) = \sum \lfloor \dfrac{n}{p_i} \rfloor\)?重複計算了 \(p_1p_2 \mid x\) 的數量。
因此,我們對上式做一個容斥,得到
\(O(\sqrt n)\) 內求 \(\phi(n)\)
將質因數分解的過程與求 \(\phi\) 結合,直接套用公式。
結束迴圈時,\(n\) 一定是一個大於 \(\sqrt n\) 的質數,指數不可能超過 \(1\),因此直接乘 \(n - 1\)。
ll get_phi(ll n) {
ll phi = 1;
for(int i = 2; i <= n / i; ++ i) {
if(n % i == 0) {
phi *= (i - 1);
n /= i;
while(n % i == 0) n /= i, phi *= i;
}
}
if(n > 1) phi *= (n - 1);
return phi;
}
\(O(n)\) 求 \([1, n]\) 的尤拉函式
與尤拉篩相結合。
任意 \(n = p_1^{\alpha_1} \times p_2^{\alpha_2} \ldots \times p_k^{\alpha_k}\),只會被 \(i = p_1^{\alpha_1 - 1} \times p_2^{\alpha_2} \ldots \times p_k^{\alpha_k}\) 和 \(p_1\) 篩到。
- 若 \(p_1 > 1\),\(\phi(n) = \phi(i) \times p_1\)。
- 若 \(p_1 = 1\),\(\phi(n) = \phi(i) \times (p_1 - 1)\)。
int not_prime[N], prime[N], idx, phi[N];
void get_phi(int n) {
phi[1] = 1;
for(int i = 2; i <= n; ++ i) {
if(!not_prime[i]) prime[++ idx] = i, phi[i] = i - 1;
for(int j = 1; j <= idx && prime[j] * i <= n; ++ j) {
not_prime[prime[j] * i] = 1;
if(i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
尤拉定理
- 如果 \(\gcd(n, P) = 1\),那麼 \(n^{\phi(P)} \equiv 1(\bmod P)\)。
費馬小定理
當 \(P\) 本身即為質數時,得到尤拉定理的特殊形式,
求逆元
整數 \(n\) 在模 \(P\) 意義上存在逆元,當且僅當 \(\gcd(n, P) = 1\)。
proof:方程 \(nx = Py + 1\) 有解的充要條件為 \(\gcd(n, P) = 1\)。
\(O(\log n)\) 求 \(n^{-1}\)
在滿足 \((n, P) = 1\) 的前提下,求解方程 \(nx = Py + 1\)。
\(x\) 即為 \(n^{-1}\)。
特別的,當 \(P\) 為質數時,\(n^{-1} = n^{P - 2}\),此時更常用的解法是快速冪。
\(O(n)\) 求 \([1, n]\) 的逆元
對於整數 \(i\),有 \(\lfloor \dfrac{P}{i} \rfloor \cdot i + P \% i = P\)。
所以
兩邊同乘 \(i^{-1} \cdot (P \% i)^{-1}\),得到
由於 \(P \% i < i\),可在 \(O(n)\) 時間內遞推求得。
int inv[N];
void get_inv(int n, int P) {
inv[1] = 1;
for(int i = 2; i <= n; ++ i) {
inv[i] = -(P / i) * inv[P % i] % P;
}
}
例題
CF963A
題意:求 \(\sum \limits_{i=0}^{n} s_{i} a^{n - i} b^{i}\)。
把式子化成 \(a^n\sum \limits_{i=0}^{n} s_{i} a^{- i} b^{i}\)。
後面的部分可以進一步表示為首項為 \(\sum \limits_{i=0}^{k - 1} s_{i} a^{- i} b^{i}\),公比為 \(a^{-k}b^k\),項數為 \(\lfloor \dfrac{n + 1}{k} \rfloor\) 的等比數列。
最後處理餘數。
submission
同餘方程組的一般解
擴充中國剩餘定理(EXCRT)
先考慮 \(k = 2\) 的情況。
設 \((y_{1_0}, y_{2_0})\) 是滿足 \(y_1m_1 - y_2m_2 = a_2 - a_1\) 的一組解。
有 \(y_1 = y_{1_0} + k\dfrac{m_2}{(m_1, m_2)}\)。
所以
聯立
推廣到 \(k > 2\)
給出合併兩組方程的實現,其中 mul
是龜速乘。
auto merge(ll a1, ll m1, ll a2, ll m2) {
ll y1, y2;
ll r = exgcd(m1, m2, y1, y2);
if((a2 - a1) % r != 0) {
cout << "NO";
exit(0);
}
ll m = m1 / r * m2;
y1 = mul(y1, (a2 - a1) / r, m);
ll a = (mul(y1, m1, m) + a1) % m;
return make_pair(a, m);
}
例題
POJ2891
submission
POJ1006
submission
CF338D
題意:給定 \(n\),\(m\) 和長度為 \(k\) 的序列,詢問是否存在 \(1 \le x \le n\),\(1 \le y \le m - k + 1\),使得 \(\forall a[i] = \gcd(x, y + i - 1)\) 成立。
根據題意,一定有 \(\forall a_i \mid x,a_i \mid y + i - 1\),列出同餘方程。
設 \(L = [a_1, a_2, \dots, a_k]\),顯然有
對於 \(x = \lambda \cdot L\),必須滿足 \(\gcd(\lambda, y) = 1\),否則 \(\gcd(x, y) > a_1\)。
\(x\) 欽定的情況下,我們要最小化 \(y\),否則會越界。
\(\lambda> 1\) 只會對 \(y\) 造成限制。
\(\rightarrow x = L\) 最優。
此時
所以只需檢驗 \(x = L\),\(y\) 等於滿足 \(y \equiv y_0\) 的最小正整數解即可。
submission
同餘方程組的構造解
中國剩餘定理(CRT)
適用範圍:模數兩兩互質。
設 \(M = [m_1, m_2, \cdots, m_k] = \prod m_i\)。
根據一般解的結論,\(x \equiv x_0 \pmod M\)。
待定係數:\(x \equiv \lambda_1a_1 + \lambda_2a_2 + \cdots + \lambda_ka_k \quad \pmod M\)。
滿足第 \(i\) 個方程的充分條件是:
令 \(M_i = \dfrac{M}{m_i}\),\(M_i'M_i \equiv 1 \pmod {m_i}\)。
則
擴充尤拉定理
尤拉降冪公式
證明
yifusuyi's blog
例題
CF17D
題意:求 \((b - 1) b^{n - 1} \% c\),\(n, b \le 10^{10^6}\),\(c \le 10^9\)。
討論 \(n - 1\) 與 \(\phi(c)\) 的關係,套用公式。
submission
CF906D
題意:給定數列 \(a_1,a_2,...,a_n\) 和模數 \(m\),每次詢問一個區間 \([l,r]\),求 \(a_l^{a_{l+1}^{{...}^{a_r}}} mod m\) 的值。
考慮求 \(a_1^{a_2^{{...}^{a_k}}}\)。
遞迴地降冪。
第 \(1\) 層:討論 \(a_1^{a_2^{{...}^{a_k}}}\) 與 \(\phi_1 = m\) 的關係,試圖往 \(0\) 層降冪(實際沒有)。
第 \(2\) 層:討論 \(a_2^{a_3^{{...}^{a_k}}}\) 與 \(\phi_2 = \phi(\phi_1)\) 的關係,往第 \(1\) 層降冪。
第 \(3\) 層:討論 \(a_3^{a_4^{{...}^{a_k}}}\) 與 \(\phi_3 = \phi(\phi_2)\) 的關係,往第 \(2\) 層降冪。
\(\vdots\)
第 \(k\) 層:討論 \(a_k\) 與 \(\phi_k = \phi(\phi_{k - 1})\) 的關係,往第 \(k - 1\) 層降冪。
直接做是 \(O(nq\log V)\) 的,(每層回溯算結果要一隻 log)。
如何最佳化?
當第 \(i\) 層的 \(\phi_i = 1\) 時,始終滿足 \(a_i^{a_{i + 1}^{{...}^{a_k}}} \ge 1\),因此直接返回 \(1\)。
由於尤拉函式衰減很快,總複雜度 \(O(q\log^2V)\)。
submission
威爾遜定理
當 \(p\) 為質數時,有
證明
當 \(p = 2\) 時,\((2 - 1)! \equiv -1 \pmod 2\)
當 \(p > 2\) 時,即證 \(\prod\limits_{i = 2}^{p - 2} \equiv 1 \pmod p\)
方程 \(x^2 \equiv 1 \pmod p\) 成立當且僅當 \(x \equiv 1\) 或 \(x \equiv p - 1\)
所以 \(\forall x \in [2, p - 2]\),\(x^{-1} \in [2, p - 2]\) 且 \(x^{-1} \ne x\)
也就是 \(\dfrac{n - 3}{2}\) 對數兩兩匹配互為逆元。
推廣
合數 \(n = p_1^{\alpha_1}\dots p_k^{\alpha_k}\)。
當 \(n\) 不為完全平方數時,\(p_1 \ne \dfrac{n}{p_1}\) 且 \(p_1, \ \dfrac{n}{p_1} < n\),所以 \(n \mid (n - 1)!\)。
當 \(n = p^2 時\):
如果 \(2p < n\),\(2p^2 \mid (n - 1)!\)
否則 \(n = 4\),\((4 - 1)! \equiv 2 \pmod 4\)
簡單排列組合
隔板法
引入
求不定方程 \(x_1 + x_2 + \dots + x_k = n\) 的解的數量,滿足 \(x_i \in N^*\),\(x_i \ge 1\)。
假想 \(n\) 個球,想要劃分為不為空的 \(k\) 段。
這個問題等效於在 \(n - 1\) 個空隙中選出 \(k - 1\) 個並插入隔板。
所以解的數量為 \(C_{n - 1}^{k - 1}\)。
推廣
1.求 $ x_1 + x_2 + \dots + x_k \le n$ 的解的數量,\(\forall x_i \ge a_i\)。
令 \(y_i = x_i - a_i + 1\),此時 \(y_i \ge 1\)。
將問題化歸為 \(\sum \limits_{i = 1}^k y_i = n - \sum\limits_{i = 1}^k a_i + k\) 的解的數量,即可用上述結論求解。
特別的,當 \(\forall a_i = 0\) 時,方案數為 \(C_{n + k - 1}^{k - 1}\)。
2.求 $ x_1 + x_2 + \dots + x_k \le n$ 的解的數量。
增設 \(x_{k + 1} \ge 0\),滿足 \(\sum \limits_{i = 1}^{k + 1} x_i = n\),用上述結論求解。
網格路徑計數
問題引入:在 \(n \times m\) 的網格上,每次只能向右或向下,求 \((0, 0)\) 走到 \((n, m)\) 的路徑數。
法1:\(O(nm)\) dp。
法2:組合意義。
把路徑等效成長度為 \(n + m\) 的操作序列,只包括 '右' 和 '下' 兩種元素。
一種方法是套用多重集不同排列的結論,方案為 \(\dfrac{(n + m)!}{n!m!}\)。
另一種方法是先假設操作序列空白,從中選 \(n\) 個填入 '下',其餘填 '右',方案為 \(C_{n + m}^{m}\)。
例題
CF630C
題意:求有多少長度不大於 \(n\),只含 '7','8' 的數字, \(n \le 55\)。
資料很小,暴力求 \(\sum \limits_{i = 1}^{n} 2_i\) 沒問題,也可以直接算 \(2^{n + 1} - 2\)。
submisson
CF629A
submisson
CF817B
submisson
CF131C
submisson
CF869C
題意:三種顏色島嶼各 \(a\),\(b\),\(c\) 座,相同顏色的島嶼的距離不小於 \(3\)(或不連通),求建橋的方案數。
- 一座島不能和相同顏色的連邊。
- 一座島不能和兩座顏色相同的島連邊。
所以對於島 \(A_i\),最多向 \(B\) 連一條邊,向 \(C\) 連一條邊,且兩邊決策互不干擾。
列舉不同顏色的島間連了幾條邊。
若 \((A, B)\) 連了 \(i\) 條邊,則可選方案為 \(C_a^i \times C_b^i \times i!\)。
分開計算兩兩間的合法方案,最後相乘。
submisson
CF300C
題意:只含 \(a\),\(b\) 的數是好數,數位之和也是 '好數' 的 '好數' 是 '極好的數',求長度為 \(n\) 的 '極好的數' 個數。
數位之和取決於數字中 \(a\),\(b\) 的個數。
列舉有 \(i\) 個 \(a\)。
若 \(i \times a + (n - i) \times b\) 是 '好數',則在答案中加上 \(\dfrac{n!}{i!(n - i)!}\)。
submission
CF1312D
題意:求滿足如下條件的長度為 \(n\) 的序列 \(a\) 的個數:
- \(\forall 1 \leq i \leq n\),都有 \(1 \leq a_i \leq m\)。
- \(a\) 中存在且僅存在一對相同的元素
- 存在一個位置 \(p\),使得 \(a_1 \sim a_p\) 為嚴格單增序列,\(a_p \sim a_n\) 為嚴格單減序列。
\(2 \leq n\le m \leq 2 \times 10^5\)。
欽定一對相同的元素 \(v\),剩下 \(n - 2\) 個數互不相同,共 \(C_{m - 1}^{n - 2}\) 種。
由於 \(a_p\) 一定大於 \(v\),減去所有數都小於 \(v\) 的 \(C_{v - 1}^{n - 2}\) 種情況。
至此,我們把整個序列劃分為 【左 $\ \ \ v \ \ $ 左 $\ \ \ a_p \ \ $ 右 $\ \ \ v \ \ $ 右】。
還未分配的 \(n - 3\) 個元素要麼在左,要麼在右,與 \(2^{n - 3}\) 種合法方案一一對應。
所以答案為 \(2^{n - 3} \sum (C_{m - 1}^{n - 2} - C_{v - 1}^{n - 2})\)
submission
CF991E
題意:給定正整數 \(n \le 10^{18}\),求滿足條件的 \(m\) 的個數:
- \(m\) 沒有前導零。
- \(m\) 中的數字 \(n\) 中都出現過。
- \(n\) 中的數字 \(m\) 中都出現過。
與 CF300C 相同,列舉每個數字的個數。
設 \(c_i\) 表示數字 \(i\) 出現的個數。
根據均值不等式,\(\prod \limits_{i = 0}^{9} c_i \le (\dfrac{\sum \limits_{i = 0}^{9} c_i}{10}) ^ {10} \le 613.11\),所以直接列舉的複雜的是正確的。
設 \(m = \sum \limits_{i = 0}^{9} c_i\),即當前數字位數。
討論貢獻:
- \(c_0 = 0 \rightarrow \dfrac{m!}{\prod \limits_{i = 0}^{9} c_i ! }\)
- \(c_0 \neq 0 \rightarrow \dfrac{m!}{\prod \limits_{i = 0}^{9} c_i ! } - \dfrac{(m - 1)!}{(c_0 - 1)!\prod \limits_{i = 1}^{9} c_i ! }\)
submission
CF140E
題意:一棵 \(n\) 層的樹,每層由 \(l_i\) 個小球組成。
-
同一層相鄰的小球的顏色都不相同。
-
相鄰的兩層的小球顏色集合不相同。
一共有多少種合法裝飾方案,對 \(p\) 取模。
欽定顏色列表 \([c_1, c_2, c_3, \dots, c_i, \cdots]\),令 \(f_{i, j}\) 表示一層內前 \(i\) 個位置恰好用前 \(j\) 種顏色的方案。
- 如果 \([1, i - 1]\) 用了 \(j - 1\) 種顏色,位置 \(i\) 只能放 \(c_j\)。
- 如果 \([1, i - 1]\) 用了 \(j\) 種顏色,位置 \(i\) 可以放 \(c_k\),\(c_k != a_{i - 1}\)。
因此
令 \(g_{i, j}\) 表示第 \(i\) 層,欽定顏色列表,且恰好用 \(j\) 種顏色的方案,
\(s_i\) 表示第 \(i\) 層的方案總數。
由於每層的顏色列表可以隨意選擇並排列:
\(g_{i, j}\) 不能從全部 \(s_{i - 1}\) 種前置狀態轉移過來,
如果 \(j \le l_{i - 1}\),則有 \(g_{i - 1, j} \times j!\) 個狀態與當前欽定的顏色集合相同,所以
注意:
- 本題的 \(p\) 不是特殊的,採用 \(A_m^i = \prod \limits_{j = 1}^{i} (m - j + 1)\) 計算。
submission
HDU7133
題意:長度為 \(n\) 的所有排列按字典序排序組成長度為 \(n!n\) 的新序列,有多少子串是 \(m\) 元排列?
完整排列的方案
把 \(\{1, 2, \dots, m - 1, m\}\) 看作整體,與剩餘 \(n - m\) 個數進行排列。
算上內部順序共 \(m!(n - m + 1)!\)。
跨塊方案
Hint 1:已知排列 \(\{p_i\}\),怎麼構造下一個排列?
- 找到最大的 \(k\) 使得 \(\{p_{k + 1}, \dots ,p_n\}\) 是最長下降字尾,即 \(p_k < p_{k + 1}\),\(\forall i \in [k + 1, n), p_i > p_{i + 1}\),
- 將 \(p_k\) 與字尾中第一個大於他的數字交換。
- 將 \(\{p_{k + 1}, \dots ,p_n\}\) 升序排序。
eg:13542 最長下降字尾為 542,前一位為 3,交換 3 和 4 得到 14532,重新排序得到 14235,即為下一個排列。
假設當前排列為 \(\{p_i\}\),下一個排列為 \(\{q_i\}\)。
性質 1:\(\{p_i\}\) 首尾元素 \(\le m\),大於 \(m\) 的都在中間。
\(A\) | \(B\) | \(C\) |
---|---|---|
\(\le m\) | \(> m\) | \(\le m\) |
最終排列由 \(\{p_i\}\) 的 \(C\) 和 \(\{q_i\}\) 的 \(A\) 構成。
所以 \(\forall i \in C, p_i \le m\)。
把中間 \(n - m\) 個元素當成整體,插入剩下 \(m\) 個元素的 \(m - 1\) 個空隙中。
滿足性質 1 的方案有 \(m!(n - m)!(m - 1)\)。
假設存在 \(i \in A, p_i > m\),則存在 \(i \in B, p_i \le m\)。
根據提示 1,最長字尾不存在於 \(A\),\(A\) 中元素不發生改變,\(\forall i \in A, p_i = q_i\)。
而 \(\forall i \in A, q_i \le m\),矛盾。
性質 2:\(\{p_i\}\) 的首部與 \(\{p_i\}\) 完全相同。
由性質 1 推出,\(A_p\) 與 \(C_p\) 關於 \(\{1, 2, \dots, m\}\) 互補。
又因為 \(C_p\) 與 \(A_q\) 互補,所以 \(A_p = A_q\)。
不滿足性質 2 當且僅當首部發生改變,也就是 \(BC\) 段嚴格遞減。
列舉尾部長度,不滿足性質的方案共 \((n - m)!\sum \limits_{i = 1}^{m - 1} C_m^i (m - i)! = m!(n - m)!\sum \limits_{i = 1}^{m - 1} \dfrac{1}{i!}\)。
預處理 \(\dfrac{1}{i!}\) 字首和,跨塊總貢獻為 \(m!(n - m)! (m - 1 - \sum \limits_{i = 1}^{m - 1} \dfrac{1}{i!})\)
submission
容斥原理
引入
- 求 \(1\) 到 \(n\) 中既不是 \(2\) 的倍數也不是 \(3\) 的倍數的個數。
-
求 1 到 \(n\) 的全排列中 \(1\) 和 \(2\),\(3\) 和 \(4\) 都不相鄰的方案。
將 \(1\),\(2\) 繫結,\(1\),\(2\) 相鄰的方案數為 \(2!(n - 1)!\),同理 \(3\),\(4\)。
- \(n\) 件不同物品放入 \(3\) 個不同盒子,求方案數。
- 無限制條件 \(\rightarrow 3^n\)
- A(B,C)為空 \(\rightarrow 2^n\)
- AB(AC,BC)為空 \(\rightarrow 1\)
- ABC 為空 \(\rightarrow 0\)
一般形式
貢獻法證明。
\(\forall x \in S - \bigcup\limits_{i = 1}^n A_i\),都在 \(i = 0\) 時產生 \(1\) 的貢獻。
如果 \(x \in A_1, A_2, A_3, \dots, A_k\),則產生 \(\sum\limits_{i = 1}^{k} (-1)^i C_k^i\) 的貢獻。
將 \((1 + 1)^k\) 與 \((1 - 1)^k\) 的二項式展開相加得到 \(C_k^i\) 的偶數項和,相減得到奇數項和。
可以證明 \(\sum\limits_{i = 1}^{k} (-1)^i C_k^i = 0\)。
- \(m\) 個物品分配給 \(n\) 個人,每個人至少一件,求分配方案數。
- \(2n\) 個元素 \(a_1, a_2, \dots, a_n\) 和 \(b_1, b_2, \dots, b_n\),求有多少個排列滿足任意 \(a_i\) 不與 \(b_i\) 相鄰。
- 尤拉函式證明。
不定方程的解的數量
求不定方程 \(x_1 + x_2 + \dots + x_k = n\) 的解的數量,滿足 \(x_i \in N\),\(l_i \le x_i \le r_i\)。
只有下界的情況在隔板法中講過。
利用容斥原理,把問題轉化為 \(\forall i, x_i \ge l_i\) 的方案減去 \(\exists i, x_i \ge r_i + 1\) 的方案。
令 \([x]\) 表示一組解。
- \(S \leftarrow \{[x] \mid \forall i, \ x_i \ge l_i\}\)
- \(A_i \leftarrow \{[x] \mid a_i \ge r_i + 1, \quad \forall j \ne i, \ x_j \ge l_j\}\)
其中
等效於列舉 \(x_i\) 的下界是 \(l_i\) 還是 \(r_i + 1\),複雜度 \(O(2^k)\)。
錯排問題
求 \(\forall i \in [1, n], a_i \le i\) 的排列數。
- \(S \leftarrow \{\{p\}\}\)
- \(A_i \leftarrow \{\{p\} \mid a_i = i\}\)
性質:\(n \rightarrow +\infty,\quad d(n) \rightarrow \dfrac{1}{e}\)。
容斥原理的符號形式
設 \(S\) 是一個有限集,\(a_1, a_2, \dots, a_n\) 是 \(n\) 種性質。
- 記 \(N(a_i)\) 為 \(S\) 中有 \(a_i\) 性質的元素的數量。特殊的,記 \(N(1) = |S|\)。
- 記 \(N(1 - a_i)\) 為 \(S\) 中沒有 \(a_i\) 性質的元素的數量。
- \(N(a_{i_1}a_{i_2}\dots a_{i_k})\) 為 \(S\) 中同時有 \(a_{i_1}, a_{i_2},\dots, a_{i_k}\) 性質的元素的數量。
- \(N(a \pm b) = N(a) \pm N(b)\)。
- 當且僅當 \(a\) 與 \(b\) 獨立時 \(N(ab) = N(a)N(b)\)。
則容斥原理可以寫成
公式中列舉的 \(i\) 表示不滿足的性質數。
符號形式在集合關係與多項式運算之間建立了橋樑。
- \((1 - A)(1 - B) = 1 - (A + B) + AB\)
- \(|S - A \cup B| = |S| - (|A| + |B|) + |A \cap B|\)
- \(N((1 - A)(1 - B)) = N(1 - (A + B) + AB) = |S| - (|A| + |B|) + |A \cap B|\)
容斥原理的推廣
有了符號形式,我們可以方便在總方案中表示性質的有無,並透過多項式展開求解容斥關係。
因此可以解決有些性質有,有些性質沒有的方案數。
如
- 求 \(1\) 到 \(n\) 中不是 \(2\) 也不是 \(3\) 的倍數,但是是 \(5\) 的倍數的數量。
- 求剛好有 \(k\) 個位置使得 \(p_i = i\) 的排列數。
由於 \(a_1\dots a_k\) 與 \((1 - a_{k + 1})\dots (1 - a_n)\) 獨立,能夠分開計算。
例題
NC15079
submission
NC16513
submission
NC19857
題意:\(n\) 對情侶圍成一圈,求任意情侶不相鄰的方案。
前置:長度為 \(n\) 的圓排列共 \((n - 1)!\)。
將選出的 \(i\) 對情侶繫結,將原集合等效成 \(2n - i\) 個元素進行排列。
本題卡空間,線上算組合又卡時間,容斥做法拿到 70pts 就夠了,時空複雜度更優的做法。
submission
CF547C
題意:維護一個可重集,每次查詢集合中互質數對的個數。
- 兩個數互質取決於是否有共同的質因子。
- 小於 \(5\times 10^5\) 的數最多有 \(7\) 個不同質因子。
令 \(cnt_x\) 表示當前集合中能被 \(x\) 整除的數的個數。
考慮新增一個元素 \(cur = p_1^{\alpha_1}\dots p_k^{\alpha_k}\)。
令性質 \(a_i\) 表示能被 \(p_i\) 整除。
則
刪除同理。
submission
[CQOI2012] 區域性極小值
題意:在 \(n \times m\) 的矩陣中,\(1\) 到 \(n \times m\) 的每個整數恰好出現一次,\(n \le 4, m \le 7\)。
一個數是區域性最小值當前僅當小於所有周圍的數。
給定區域性最小值的位置和非區域性最小值的位置,求滿足此要求的矩陣個數。
令性質 \(a_{i, j}\) 表示 \((i, j)\) 是區域性最小值。
則要求的方案為 \(N(a_{i_1, j_1} \dots a_{i_k, j_k} (1 - a_{i_{k + 1},j_{k + 1}})\dots (1 - a_{i_{nm},j_{nm}}))\)。
於是轉化為求解子問題 \(N(\prod a_{i, j})\)。
\(4 \times 7\) 的矩陣中最多有 \(8\) 個區域性最小值,所以子問題規模小於 \(\sum\limits_{i = 0}^{8} C_{28}^i\),大約在 \(10^4\),可以接受。
透過搜尋列舉子問題。
當欽定某些位置是區域性最小時,如何求方案數?
不妨從小到大填充矩陣。
設 \(f_{i, s}\) 表示當前填到 \(i\),且區域性最小的狀態(填/沒填)為 \(s\) 時的方案。
\(cnt_s\) 表示狀態為 \(s\) 時填了多少個欽定位置。
如果當前填的位置欽定了區域性最小,那麼 \(f_{i, s} = \sum\limits_{j \in s} f_{i - 1, s - j}\)。
如果當前填的位置沒有欽定,
用 \(nums_s\) 表示狀態 \(s\) 下已經能填的非欽定位置個數。
如
此時只有 \((2, 3)\) 能填,否則會在後續產生矛盾。
則這部分的貢獻為 \(\max(0, nums_s - (i - 1 - cnt_s)) \times f_{i - 1, s}\)。
\(i - 1 - cnt_s\) 為前 \(i - 1\) 個數中已經用掉的位置。
submission
第二類斯特林數(Stirling Number)
第二類斯特林數(斯特林子集數)\(\begin{Bmatrix}n\\ k\end{Bmatrix}\),也可記做 \(S_2(n,k)\),表示將 \(n\) 個兩兩不同的元素,劃分為 \(k\) 個互不區分的非空子集的方案數。
遞推式
我們插入一個新元素時,有兩種方案:
- 將新元素放入一個現有的非空子集,有 \(k\begin{Bmatrix}n-1\\ k\end{Bmatrix}\) 種方案。
- 將新元素單獨放入一個子集,有 \(\begin{Bmatrix}n-1\\ k-1\end{Bmatrix}\) 種方案;
邊界是 \(\begin{Bmatrix}n\\ 0\end{Bmatrix}=[n=0]\)。
通項公式
不妨先認為 \(k\) 個集合互不相同,轉化成經典容斥問題,最後乘上 \(\dfrac{1}{k!}\)。
則
重要公式
我們記下降階乘冪 \(x^{\underline{n}}=\dfrac{x!}{(x-n)!}=\prod_{k=0}^{n-1} (x-k)\)。
則可以利用下面的恆等式將普通冪轉化為下降冪:
考慮各式組合意義。
- \(x^n \rightarrow\) \(n\) 個不同的球放入 \(x\) 個不同的盒子。
- \(\begin{pmatrix}x\\ k\end{pmatrix} \rightarrow\) \(x\) 個盒子中選出 \(k\) 個。
- \(\begin{Bmatrix}n\\ k\end{Bmatrix} \rightarrow\) \(n\) 個不同的球放入 \(k\) 個相同的盒子且都不為空。
- \(k! \rightarrow\) 將選出的 \(k\) 個盒子排列。
正確性顯然。
積性函式
定義
若函式 \(f(n)\) 滿足 \(f(1)=1\) 且 \(\forall x,y\in\mathbf{N}^*,~(x,y)=1\) 都有 \(f(xy)=f(x)f(y)\),則 \(f(n)\) 為 積性函式。
若函式 \(f(n)\) 滿足 \(f(1)=1\) 且 \(\forall x,y\in\mathbf{N}^*\) 都有 \(f(xy)=f(x)f(y)\),則 \(f(n)\) 為 完全積性函式。
例如:
- 單位函式:\(\varepsilon(n)=[n=1]\)。(完全積性)
- 恆等函式:\(\operatorname{id}_k(n)=n^k\),\(\operatorname{id}_{1}(n)\) 通常簡記作 \(\operatorname{id}(n)\)。(完全積性)
- 常數函式:\(1(n)=1\)。(完全積性)
- 除數函式:\(\sigma_{k}(n)=\sum_{d\mid n}d^{k}\)。\(\sigma_{0}(n)\) 通常簡記作 \(d(n)\) 或 \(\tau(n)\),\(\sigma_{1}(n)\) 通常簡記作 \(\sigma(n)\)。
- 尤拉函式:\(\varphi(n)=\sum_{i=1}^n[(i,n)=1]\)
- 莫比烏斯函式:\(\mu(n)=\begin{cases}1&n=1\\0&\exists d>1,d^{2}\mid n\\(-1)^{\omega(n)}&\text{otherwise}\end{cases}\),其中 \(\omega(n)\) 表示 \(n\) 的本質不同質因子個數,它是一個加性函式。
"加性函式"
此處加性函式指數論上的加性函式 (Additive function)。對於加性函式 \(f\),當整數 \(a,b\) 互質時,均有 \(f(ab)=f(a)+f(b)\)。
應與代數中的加性函式 (Additive map) 區分。
性質
若 \(f(x)\) 和 \(g(x)\) 均為積性函式,則以下函式也為積性函式:
設 \(x=\prod p_i^{k_i}\)
若 \(F(x)\) 為積性函式,則有 \(F(x)=\prod F(p_i^{k_i})\)。
若 \(F(x)\) 為完全積性函式,則有 \(F(x)=\prod F(p_i)^{k_i}\)。
質因數分解求 \(f(n)\)
\(f(n) = f(p_1^{\alpha_1})\dots f(p_k^{\alpha_k})\)。
對 \(f(p_1^{\alpha_1})\) 依次求解然後相乘即可。
ll get_f(int n) {
ll ret = 1;
for(int i = 2; i <= n / i; ++ i) {
if(n % i == 0) {
int cnt = 0;
while(n % i == 0) {
++ cnt;
n /= i;
}
ret = ret * calc_f(i, cnt);
}
}
if(n > 1) {
ret = ret * calc_f(n, 1);
}
return ret;
}
尤拉篩求 \(f(1), f(2), \dots, f(n)\)
根據定義:\(f(1) = 1\)。
\(n = p_1^{\alpha_1} \dots p_k^{\alpha_k}\) 一定會被 \(m = p_1^{\alpha_1 - 1} \dots p_k^{\alpha_k}\) 篩到。
- 如果 \(\alpha_1 = 1\),則 \((n, m) = 1\),\(f(n) = f(m) \cdot f(p_1)\)。
- 如果 \(\alpha_1 > 1\),則 \((n, m) \ne 1\),\(f(n) = \dfrac{f(m)}{f(p_1^{\alpha_1 - 1})} \cdot f(p_1^{\alpha_1})\)。
因此,對於質數的冪次 \(p^{cnt}\),暴力呼叫 calc_f(p, cnt)
。
否則,記錄陣列 \(cnt_i\) 表示 \(i\) 中最小質因子的次數,根據上述分類求解。
void init(int n) {
f[1] = 1;
for(int i = 2; i <= n; ++ i) {
if(v[i] == 0) {
p[++ idx] = i;
cnt[i] = 1;
f[i] = calc_f(i, 1);
}
for(int j = 1; p[j] <= n / i; ++ j) {
v[i * p[j]] = 1;
if(i % p[j] == 0) {
cnt[i * p[j]] = cnt[p[j]] + 1;
f[i * p[j]] = f[i] / calc_f(p[j], cnt[p[j]]) * calc_f(p[j], cnt[p[j]] + 1);
break;
}
cnt[i * p[j]] = 1;
f[i * p[j]] = f[i] * calc_f(p[j], 1);
}
}
}
例題
NC229685
題意:求 \(n\) 的正因子個數,\(q\) 次詢問,\(n \le 10^7\)。
若 \(n = p_1^{\alpha_1}\dots p_k^{\alpha_k}\),則 \(f(n) = (\alpha_1 + 1)\dots(\alpha_k + 1)\)。
若 \((p, q)\) 互質,則 \(f(p)\cdot f(q) = (\alpha_1 + 1)\dots(\alpha_k + 1)(\beta_1 + 1)\dots(\beta_l + 1) = f(p\cdot q)\)
submission
NC23047
題意:求 \(\bigoplus\limits_{i = 1}^n (i^n \bmod (10^9 + 7))\),\(n \le 1.3 \times 10^7\)。
定義 \(f(i) = i^n\)。
對於 \(\forall p, q, \ \ f(pq) = (pq)^n = p^nq^n\),是完全積性的。
submission
CF757E
題意:定義函式 \(f_r(n)\):
- \(f_0(n)\) 為滿足 \(p\cdot q=n\) 且 \(\gcd(p,q)=1\) 的有序對 \((p,q)\) 個數;
- \(\displaystyle f_{r + 1}(n)=\sum_{u\cdot v=n}\frac{f_{r}(u)+f_{r}(v)}{2}\).
一共 \(q\) 組詢問,每組詢問給出 \(r,n\),求 \(f_r(n)\) 模 \(10^9+7\) 的結果。
資料範圍:\(q\le10^6\),\(0\le r\le10^6\),\(1\le n\le10^6\).
對於 \(n = p_1^{\alpha_1}\dots p_k^{\alpha_k}\),只有 \(p = \prod\limits_{i \in S}p_i^{\alpha_i} , \ q = \prod\limits_{i \notin S}p_i^{\alpha_i}\) 時會對 \(f_0(n)\) 造成貢獻。
所以 \(f_0(n) = 2^k = 2^{\sigma(n)}\).
對於 \((p, q) = 1\),\(\{p_i\} \cap\{q_i\} = \phi\).
所以 \(\sigma(pq) = \sigma(p) + \sigma(q)\).
所以 \(f_0(pq) = f_0(p)\cdot f_0(q)\),於是我們證明了 \(f_0\) 是積性函式。
現在考慮 \(r \ge 1\).
注意到 \((u, v)\) 與 \((v, u)\) 都有貢獻,所以 \(\forall d \mid n\) 對 \(f_r(n)\) 的貢獻為 \(2 \times \dfrac{f_{r - 1}(d)}{2}\)。
考慮積性函式 \(f(n)\),以及函式 \(g(n) = \sum\limits_{d\mid n}f(d)\).
對於 \((p, q) = 1\),有
所以 \(g(n)\) 也是積性函式。
因為 \(f_0\) 是積性函式,所以 \(\forall r, (p, q) = 1, \ f_r(p\times q) = f_r(p) \times f_r(q)\).
於是目標 \(f_r(n) = f_r(p_1^{\alpha_1})\times \dots \times f_r(p_k^{\alpha_k})\),只需預處理 \(\forall r, p, \alpha, \ \ f_r(p^{\alpha})\) 即可。
不妨從 \(f_0\) 開始遞推。
- \(\alpha = 0\),\(f_0 = 1\).
- \(\alpha > 0\),\(f_0 = 2\).
\(f_0(p^{\alpha})\) 的值與 \(p\) 無關。
根據遞推式 \(f_r(p^{\alpha}) = \sum\limits_{i = 0}^{\alpha} f_{r - 1}(p^i)\),\(f_r\) 只與 \(f_{r - 1}\) 有關,所以 \(\forall r\),\(f_r(p^{\alpha})\) 的值與 \(p\) 無關。
記 \(dp_{r, i} = f_r(p^i)\).
submission
莫比烏斯反演
引入
- 如果 \(f(n) = \sum\limits_{i = 1}^ng(i)\),則 \(g(n)\) 可透過 \(f(n) - f(n - 1)\) 反求。
- 如果 \(f(n) = \sum\limits_{d \mid n} g(d)\),怎麼透過 \(f\) 反求 \(g(n)\)?
如果 \(n = p_1^{\alpha_1}\dots p_k^{\alpha_k}\).
令性質 \(a_i\) 不整除 \(p_i^{\alpha_i}\),則 \(N(a_i) = f(p_1^{\alpha_1}\dots p_i^{\alpha_i - 1}\dots p_k^{\alpha_k})\).
則
引入莫比烏斯函式 \(\mu(n) = [n = p_1\dots p_i](-1)^i\).
即
於是
定理(莫比烏斯反演)
設 \(f:\mathbb{N} \rightarrow \mathbb{R}, \ g:\mathbb{N} \rightarrow \mathbb{R}\) 是兩個函式,則
環計數問題
題意:\(n\) 個數圍成一圈,每個數取值範圍在 \(1\) 到 \(r\),求有多少個這樣的環,兩個環不相同當且僅當不能透過旋轉重合。
將 \(n\) 個數展開成序列並無限延伸。
定義週期 \(d\) 為滿足 \(\forall a_i = a_i + d\) 的最小正整數。
顯然 \(d \mid n\),否則與 \(\forall a_i = a_i + n\) 矛盾。
令 \(f(d)\) 表示週期為 \(d\) 的不同環的個數。
一個環對應 \(d\) 個不同的序列(分別以 \(a_1, a_2\dots a_d\) 開頭)。
所有不同的序列共 \(r^n\) 個。
所以
總方案數為 \(\sum\limits_{d = 1}^n f(d)\).
定理(莫比烏斯反演2)
設 \(f:\mathbb{N} \rightarrow \mathbb{R}, \ g:\mathbb{N} \rightarrow \mathbb{R}\) 是兩個函式,且存在正整數 \(N\),使得 \(\forall n > N, \ f(n) = g(n) = 0\).
則
例題
NC14648
題意:給定序列 \(\{a_i\}, \ \{b_i\}\),有多少對 \((x, y) = 1\) 滿足 \(a_{b_x} = b_{a_y}\).
定義 \(g(d) = \sum\limits_{x, y}[(x, y) = d][a_{b_x} = b_{a_y}]\),考慮反演:
則
其中 \(\forall f_i\) 可以在 \(O(\dfrac{n}{1} + \dfrac{n}{2} + \cdots + \dfrac{n}{n}) = O(n\ln n)\) 內求出。
submission
AT_abc162_e
題意:給定\(n,k\),求
和上題套路一致,設 \(g(d) = \sum [\gcd(a_i) = d]\).
有反演:
若 \(d \mid \gcd(a_i)\),則 \(\forall i, \ d \mid a_i\),所以 \(f(d) = \lfloor \dfrac{k}{d} \rfloor^n\).
最終答案為 \(\sum g(d) \cdot d\).
submission
AT_agc038_c
題意:給定陣列 \(A\),求 \(S = \sum\limits_{i=1}^{N}\sum\limits_{j=i+1}^{N}\mathrm{lcm}(A_i,A_j)\) .
令 $g(d) = \sum\limits_{i, j}[(A_i, A_j) = d] \cdot\mathrm{lcm}(A_i,A_j) $.
由於 \(\mathrm{lcm}(a, b) = \dfrac{ab}{\gcd(a, b)}\),則 $\sum\limits_{d = 1}^{\max(A_i)} g(d) - \sum\limits_{i = 1}^nA_i= 2S $
最後對 \(g(d) \cdot d\) 做反演即可。
submission
狄利克雷(Dirichlet)卷積
定義
設 \(f:\mathbb{N^+} \rightarrow \mathbb{R}, \ g:\mathbb{N^+} \rightarrow \mathbb{R}\),則他們的狄利克雷卷積為
性質
-
如果 \(f(n), \ g(n)\) 是積性函式,則 \(h(n) = (f*g)(n)\) 也是積性函式。
證明:
假設 \((p, q) = 1\),則
\[\begin{aligned} h(pq) &= \sum_{\begin{aligned}d_1\mid p \\d_q\mid 2 \end{aligned}} f(d_1d_2) \cdot g(\dfrac{pq}{d_1d_2})\\ &= \sum_{\begin{aligned}d_1\mid p \\d_q\mid 2 \end{aligned}} f(d_1)\cdot f(d_2) \cdot g(\dfrac{p}{d_1})\cdot g(\dfrac{q}{d_1})\\ &= h(p) \cdot h(q) \end{aligned} \] -
\(f = g * 1 \Leftrightarrow g = f * \mu\).
證明:
\[f(n) = \sum_{d \mid n} g(n) \Longleftrightarrow g(n) = \sum_{d\mid n} \mu(n / d)\cdot f(d) \] -
滿足交換律與結合律。
\[\begin{aligned} f * g &= g * f \\ (f * g) * h &= f * (g * h) \end{aligned} \] -
\(\epsilon = \mu * 1\).
證明:
設 \(\mu\) 的和函式 \(F(n) = \sum\limits_{d \mid n}\mu(d)\).
\(F(1) = \mu(1) = 1\).
\[\begin{aligned} F(p^k) &= \mu(1) + \mu(p) + \mu(p^2) + \cdots + \mu(p^k) \\ &= 1 + (-1) + 0 + \cdots + 0\\ &= 0 \end{aligned} \]\(F(n) = \prod F(p_i^k) = 0\).
所以 \(\epsilon(n) = F(n)= [n = 1]\).
-
\(id = \phi * 1\).
即證 \(n = \sum\limits_{d \mid n} \phi(d)\).
將 \(m \in [1, n]\) 分類, \(m\) 屬於 \(C_d\) 類當且僅當 \((m, n) = d\) 即 \((m / d, n / d) = 1\).
所以 \(C_d\) 的大小為小於 \(n / d\) 且與之互素的正整數個數,恰與 \(\phi(n / d)\) 相等。
\[n = \sum|C_d| = \sum \phi(n/d) = \sum \phi(d) \] -
\(\phi = \mu * id\).
證明:
對於 \(n = p_1^{a_1} \cdots p_k^{a_k}\),令性質 \(a_i\) 表示能夠被 \(p_i\) 整除。
\[\begin{aligned} \phi(n) &= N((1 - a_1)\cdots(1 - a_k)) \\ &= \sum_{S \subseteq\{1, \dots, k\}} (-1)^{|S|} \dfrac{n}{\prod\limits _{i \in S}p_i}\\ &= \sum_{d \mid n} [d = p_{x_1}\cdots p_{x_i}] (-1)^i \dfrac{n}{i}\\ &= \sum_{d \mid n} \mu(d) \cdot \dfrac{n}{i}\\ &= (\mu * id)(n) \end{aligned} \]引理:\(\dfrac{\phi(n)}{n} = \sum\limits_{d \mid n}\dfrac{\mu(d)}{d}\)
杜教篩
引入
-
求 \(\Phi(n) = \sum\limits_{i = 1}^{n} \phi(n)\)。
對於尤拉函式,有 \(\phi * I = id\),即 \(\phi(n) = n - \sum\limits_{d \mid n, d < n}\phi(n)\)。
所以
\[\begin{aligned} \sum_{i = 1}^n\phi(i) &= \sum_{i = 1}^n (i - \sum_{d \mid i, d < i}\phi(d))\\ &= \dfrac{n(n + 1)}{2} - \sum_{i = 2}^n\sum_{d \mid i, d < i}\phi(d)\\ &= \dfrac{n(n + 1)}{2} - \sum_{\frac{i}{d} = 2}^n\sum_{d = 1}^{\lfloor\frac{n}{\lfloor\frac{i}{d}\rfloor}\rfloor}\phi(d)\\ &= \dfrac{n(n + 1)}{2} - \sum_{i = 2}^n\sum_{d = 1}^{\lfloor\frac{n}{i}\rfloor}\phi(d)\\ &= \dfrac{n(n + 1)}{2} - \sum_{i = 2}^n\Phi(\lfloor\frac{n}{i}\rfloor)\\ \end{aligned} \]於是只需預處理 \(O(\sqrt{n})\) 個 \(\Phi(\lfloor\dfrac{n}{i}\rfloor)\),就可以算出 \(\Phi(n)\)。
第三第四步將列舉因數化為列舉倍數,是常見減小複雜度的做法。
-
求 \(M(n) = \sum\limits_{i = 1}^{n} \mu(n)\)。
和尤拉函式類似,利用 \(\mu(n) = [n = 1] - \sum\limits_{d \mid n, d < n}\mu(d)\)。
\[\begin{aligned} \sum_{i = 1}^n\mu(n) &= \sum_{i = 1}^n [i = 1] - \sum\limits_{d \mid i, d < i}\mu(d)\\ &= 1 - \sum_{i = 2}^n\sum_{d \mid i, d < i}\mu(d)\\ &= 1 - \sum_{i = 2}^n\sum_{d = 1}^{\lfloor\frac{n}{i}\rfloor}\mu(d)\\ &= 1 - \sum_{i = 2}^nM(\lfloor\frac{n}{i}\rfloor)\\ \end{aligned} \]
推導
對於一個數論函式 \(f(n)\),杜教篩可以在低於線性複雜度內求 \(S(n) = \sum\limits_{i = 1}^nf(i)\).
如果利用整除分塊把相等的一起算,就加快了速度。
根據 \(f(n)\) 的性質,構造 \(S(n)\) 關於 \(S(\lfloor\dfrac{n}{i}\rfloor)\) 的遞推式,方法如下。
構造兩個積性函式 \(h, \ g\),滿足 \(h\) 易於求和,\(g\) 易於計算 且\(h = f * g\)。
則 \(h(i) = \sum\limits_{d \mid i}g(d)\cdot f(\dfrac{i}{d})\),對 \(h(i)\) 求和,有
-
公式法求 \(\sum_{i = 1}^n\phi(n)\)。
\(h = id, \ f = \phi, \ g = I\)。
所以 \(\sum\limits_{i = 1}^n id(i) = \sum\limits_{i = 1}^n S(\lfloor\dfrac{n}{d}\rfloor)\),即 \(S(n) = \sum\limits_{i = 1}^n id(i) - \sum\limits_{i = 2}^n S(\lfloor\dfrac{n}{d}\rfloor)\)。
同理,可用 \(\epsilon = \mu * I\) 求出 \(M(n)\)。
實現
對於 \(n < N^{\frac{2}{3}}\) 預處理,否則暴力遞迴然後記憶化。
複雜度證明:[Auferstanden].
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;
using uint = unsigned int;
using ll = long long;
constexpr int N = 3e6 + 5, V = 3e6;
__gnu_pbds::gp_hash_table<int, int> Mu;
__gnu_pbds::gp_hash_table<int, ll> Phi;
int mu[N], p[N], v[N], idx;
ll phi[N];
void init() {
phi[1] = mu[1] = 1;
for(int i = 2; i <= V; ++ i) {
if(v[i] == 0) {
mu[i] = -1;
phi[i] = i - 1;
p[++ idx] = i;
}
for(int j = 1; j <= idx && p[j] <= V / i; ++ j) {
v[i * p[j]] = 1;
if(i % p[j] == 0) {
phi[i * p[j]] = phi[i] * p[j];
mu[i * p[j]] = 0;
break;
}
mu[i * p[j]] = -mu[i];
phi[i * p[j]] = phi[i] * (p[j] - 1);
}
}
for(int i = 1; i <= V; ++ i) {
mu[i] += mu[i - 1];
phi[i] += phi[i - 1];
}
}
ll get_Phi(uint n) {
if(n <= V) return phi[n];
if(Phi.find(n) != Phi.end()) return Phi[n];
ll ans = (ll)n * (n + 1) / 2;
for(uint i = 2, j; i <= n; i = j + 1) {
if(n / i == 0) break;
j = n / (n / i);
ans -= get_Phi(n / i) * (j - i + 1);
}
return Phi[n] = ans;
}
int get_Mu(uint n) {
if(n <= V) return mu[n];
if(Mu.find(n) != Mu.end()) return Mu[n];
int ans = 1;
for(uint i = 2, j; i <= n; i = j + 1) {
if(n / i == 0) break;
j = n / (n / i);
ans -= get_Mu(n / i) * (j - i + 1);
}
return Mu[n] = ans;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
init();
int T;
cin >> T;
while(T --) {
uint n; cin >> n;
cout << get_Phi(n) << ' ' << get_Mu(n) << '\n';
}
return 0;
}
矩陣乘法
引入
如果 \(C = AB\),則 \(c_{ij} = \sum\limits_{k = 1}^{n}a_{ik} \cdot b_{kj}\),即 \(A\) 的第 \(i\) 行與 \(B\) 的第 \(j\) 列的點積。
-
假設有 \(n\) 個地點,\(i\) 到 \(j\) 做飛機有 \(a_{ij}\) 種選擇,坐火車有 \(b_{ij}\) 種選擇。求從 \(i\) 先做飛機再坐火車到 \(j\) 的方案。
列舉中轉點 \(k\)。
\(c_{ij} = \sum\limits_{k = 1}^na_{ik}\cdot b_{kj}\),寫成矩乘即 \(C = AB\)。
矩陣快速冪最佳化線性遞推
-
\(f(n) = a_1f(n - 1) + a_2f(n - 2) + a_3f(n - 3)\).
\[\begin{pmatrix} f_n\\ f_{n - 1}\\ f_{n - 2}\\ \end{pmatrix} = \begin{pmatrix} a_1 & a_2 & a_3\\ 1 & 0 & 0 \\ 0 & 1 & 0 \\ \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ f_{n - 2}\\ f_{n - 3}\\ \end{pmatrix} \] -
\(f(n) = a_1f(n - 1) + a_2f(n - 2) + C\).
\[\begin{pmatrix} f_n\\ f_{n - 1}\\ C \end{pmatrix} = \begin{pmatrix} a_1 & a_2 & 1\\ 1 & 0 & 0\\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ f_{n - 2}\\ C \end{pmatrix} \]或
\[\begin{pmatrix} f_n\\ f_{n - 1}\\ 1 \end{pmatrix} = \begin{pmatrix} a_1 & a_2 & C\\ 1 & 0 & 0\\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ f_{n - 2}\\ 1 \end{pmatrix} \] -
\(f(n) = a_1f(n - 1) + a_2f(n - 2) + c_2n^2 + c_1n + c_0\).
\[\begin{pmatrix} f_n\\ f_{n - 1}\\ (n + 1)^2\\ n + 1\\ 1 \end{pmatrix} = \begin{pmatrix} a_1 & a_2 & c_2 & c_1 & c_0\\ 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 2 & 1 \\ 0 & 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 0 & 1 \\ \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ f_{n - 2}\\ n^2\\ n\\ 1 \end{pmatrix} \] -
\(f(n) = a_{11}f(n - 1) + a_{12}g(n - 1), \ g(n) = a_{21}f(n - 1) + a_{22}g(n - 2)\).
\[\begin{pmatrix} f_n\\ g_n\\ \end{pmatrix} = \begin{pmatrix} a_{11} & a_{12}\\ a_{21} & a_{22}\\ \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ g_{n - 1}\\ \end{pmatrix} \] -
若 \(f(n)\) 與 \(g(n)\) 是線性遞推的,則 \(h(n) = f(n)\cdot g(n)\) 也能線性遞推。
\[\begin{aligned} &\\ f(n) &= f(n - 1) + f(n - 2)\\ &\\ f^2(n) &= f^2(n - 1) + f^2(n - 2) + 2\cdot f(n - 1) \cdot f(n - 2)\\ &\\ f(n - 1) \cdot f(n - 2) &= \begin{cases} f(n - 1)\cdot (f(n - 1) - f(n - 3)) \\ (f(n - 2) + f(n - 3))\cdot f(n - 2) \end{cases}\\ &\\ 2\cdot f(n - 1) \cdot f(n - 2) &= f^2(n - 1) + f^2(n - 2) - f^2(n - 3)\\ &\\ f^2(n) &= 2\cdot f^2(n - 1) + 2\cdot f^2(n - 2) - f^2(n - 3) \end{aligned} \]
例題
CF1117D
題意:有多少長度為 \(n\) 的 \(01\) 串,使得任意極長全 \(0\) 字串的長度都被 \(m\) 整除?(\(n \le 10^{18}, \ m \le 100\))
定義 \(f_{i, 0/1}\) 為長度為 \(i\),結尾為 \(0/1\) 的方案數。
上下相加得到 \(f_i = f_{i - 1} + f_{i - m}\)。
構造矩陣乘法加速遞推。
於是有 \(F_{n} = AF_{n - 1} = A^2F_{n - 2} = A^{n - m}F_m\)。
預處理 \(F_m\),時間複雜度 \(O(m + m^3\log n)\)。
注意特判 \(n < m\) 的情況。
submission
NC17890
題意:\(m \times n\) 的方格,每個格子可以填白色或黑色,左右兩個不同為白,左右兩列不同為全黑,求合法方案數。(\(n\le10^{18}, m \le5\))
先樸素動態規劃。
\(f_{i, s}\) 表示第 \(i\) 列狀態為 \(s\) 時的方案,'0' 表示白,'1' 表示黑。
考慮 \(s\) 能從哪些 \(s'\) 轉移來。
- \(s\ |\ s' = 2^m - 1\)。
- 若 \(s = 2^m - 1\),\(s'\ne 2^m - 1\)。
所以
又可以看成 \(F_n = A\cdot F_{n - 1} = A^{n - 1}\cdot F_1\) 的形式。
submission
CF718C
題意:給定數列 \(\{a\}\),支援兩種操作。
- 區間 \([l, r]\) 加 \(x\)。
- 求 \(\sum_{i = l}^rf(a_i)\),\(f(1) = f(2) = 1, \ f(n) = f(n - 1) + f(n - 2)\)。
寫成向量的形式
根據遞推式,可以寫出 \(\vec F(0) = \begin{pmatrix}1\\0\end{pmatrix}\)。
於是可以用 \(\vec{F(a_i)}_{1, 1}\) 來替代原序列,將操作轉化為
- 區間 \([l, r]\) 左乘 \(\begin{pmatrix} 1 & 1\\ 1 & 0\\ \end{pmatrix}^x\)。
- 查詢 \(\sum_{i = l}^r\vec{F(a_i)}_{1, 1}\)。
用一個 \(2 \times 1\) 的向量表示線段樹的節點,\(2 \times 2\) 的向量表示懶標記,維護區間矩陣乘法。
submission
P6327 區間加區間 sin 和
題意:給出一個長度為 \(n\) 的整數序列 \(a_1,a_2,\ldots,a_n\),進行 \(m\) 次操作,操作分為兩類。
操作 \(1\):給出 \(l,r,v\),將 \(a_l,a_{l+1},\ldots,a_r\) 分別加上 \(v\)。
操作 \(2\):給出 \(l,r\),詢問 \(\sum\limits_{i=l}^{r}\sin(a_i)\)。
\(\sin(x + v)\) 和 \(\cos(x + v)\) 都是線性遞推的。
線段樹維護即可。
submission
斐波*
題意:斐波那契數列 \(\{fib\}\) 滿足
\(S\) 是一個可重集合 \(\left\{s_1,s_2,...,s_{|S|}\right\}\)。
\(f(S)\) 定義為
支援兩種操作。
- 把 \(a_p\) 變為 \(v\)。
- 計算 \(\sum_{i=l}^{r}\sum_{j=i}^{r}f(\left\{a_i,a_{i+1},..,a_j\right\})\) 。
定義 \(g(n) = fib^2(n)\)。
證明參考上文 矩陣快速冪最佳化線性遞推.5。
寫成向量形式。
雖然 \(\vec{G(0)}\) 不存在,但仍可透過遞推式求出 \(\vec{G(0)} = \begin{pmatrix}0\\1\\1\\\end{pmatrix}\)。
用向量的第一個元素表示答案。
往集合裡新增一個元素 \(a\)。
其中 \(I\) 是單位矩陣。
所以
將 \((I + A^{a_i})\) 視作元素 \(v_i\)。
題目要求的 \(\sum_{i=l}^{r}\sum_{j=i}^{r}f(\left\{a_i,a_{i+1},..,a_j\right\})\) 即
即區間 \([l, r]\) 內所有子區間的元素積之和。
考慮分治。
將 \([l, r]\) 分為 \([l, mid]\) 和 \([mid + 1, r]\)。
討論貢獻來源,令 \(\{l, r\}\) 表示 \(\prod_{i = l}^r v_i\)。
- 子區間單獨屬於左區間或右區間,向下遞迴。
- 子區間跨塊,貢獻為 \(\sum\limits_{i = l}^{mid}\{i, mid\} \cdot \sum\limits_{i = mid + 1}^{r} \{mid + 1, i\}\).
具體實現用線段樹內維護 \(4\) 個資訊。
對於代表區間 \([l, r]\) 的節點。
- \(ans\) 表示 \([l, r]\) 的答案。
- \(self = \prod_{i = l}^r v_i\)
- \(left = \sum_{i = l}^r\{l, i\}\)
- \(right = \sum_{i = l}^r\{i, r\}\)
struct Node {
Matrix ans, self, l, r;
Node() { self = I; }
void operator = (Matrix x){
ans = self = l = r = x;
}
friend Node operator + (Node L, Node R) {
Node x;
x.ans = L.ans + R.ans + L.r * R.l;
x.self = L.self * R.self;
x.l = L.l + R.l * L.self;
x.r = R.r + L.r * R.self;
return x;
}
} t[N << 2];
submission
線性方程組
Gauss-Jordan 消元法
思想很簡單,即
- 選主元。
- 選主元不為零的行為主行。
- 用主行消去主行外的所有主元。
判斷無解或無窮解。
如果最終增廣矩陣如下。
最後一行係數矩陣為零,而增廣矩陣非零,無解。
如果增廣矩陣也為零呢?
可以得到
其中 \(x_2, \ x_4 \in \R\) ,有無窮多組解,\(x_2, \ x_4\) 確定,則解確定。
增廣矩陣每一行第一個非零元對於的變數稱為 首變數(lead variable),化簡過程種跳過的變數稱為 自由變數(free variable)。
因此 \(x_1, x_3, x_5\) 為首變數,\(x_2, x_4\) 為自由變數。
實現:P2455 [SDOI2006] 線性方程組。
時間複雜度 \(O(n^3)\)。
#include<bits/stdc++.h>
using namespace std;
using db = double;
constexpr int N = 105;
db a[N][N];
int n;
bool neq(db x, db y) {
return fabs(x - y) > 1e-6;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n;
for(int i = 1; i <= n; ++ i) {
for(int j = 1; j <= n + 1; ++ j) {
cin >> a[i][j];
}
}
int cur = 1;
for(int k = 1; k <= n; ++ k) { \\ 選主元
for(int i = cur; i <= n; ++ i) {
if(neq(a[i][k], 0)) { \\ 選主行
for(int j = k; j <= n + 1; ++ j) {
swap(a[cur][j], a[i][j]);
}
break;
}
}
if(neq(a[cur][k], 0)) { \\ 消元
db x = a[cur][k];
for(int j = k; j <= n + 1; ++ j) {
a[cur][j] /= x;
}
for(int i = 1; i <= n; ++ i) {
if(i == cur) continue;
db x = a[i][k];
for(int j = k; j <= n + 1; ++ j) {
a[i][j] -= x * a[cur][j];
}
}
++ cur; \\ 主行移至下一行
}
}
for(int i = cur; i <= n; ++ i) {
if(neq(a[i][n + 1], 0)) {
cout << -1;
exit(0);
}
}
if(cur != n + 1) {
cout << 0;
}
else {
for(int i = 1; i <= n; ++ i) {
cout << "x" << i << "=" << fixed << setprecision(5) << a[i][n + 1] << '\n';
}
}
return 0;
}
異或方程組
異或可看成模 \(2\) 意義下的加法,寫法與加法無異。
有幾個最佳化的點。
bitset<N> a[N]
替代係數矩陣。- 交換用
swap(a[i], a[cur])
。 - 消元用
a[i] ^= a[cur])
。
時間複雜度 \(O(\dfrac{n^3}{w})\)。
例題
POJ1222
題意:\(5 \times 6\) 的方格,改變一盞燈的狀態會改變周圍所有燈的狀態,給出一種開關方案使得所有燈熄滅。
令 \(x_{i, j} = 0 / 1\) 表示 \((i, j)\) 有無操作。
如果 \((i, j)\) 初狀態為 \(a_{i, j}\),則達到末狀態需要滿足 \(a_{i, j} \oplus\)
對 \(30\) 個未知數與 \(30\) 個方程進行高斯消元。
如果處理無窮多組解的情況?將自由變數全賦值為 \(0\),第 \(i\) 行的首變數即列的增廣一列的值。
submission
CF1344F
題意:一個包含三原色 RYB
的序列混合的結果定義為:
- 如果序列開頭兩項顏色相同,將這兩項刪去。
- 如果序列開頭兩項顏色不同,將這兩項替換為與這兩種顏色不同的顏色。
- 特別地,如果序列為空,則混合的結果是白色
W
。
有一個長為 \(n\) 的顏色序列(某些位置為空),給出 \(k\) 個操作:
mix
:選擇一個子序列和混合時的順序(忽略空位置),給出其混合後的結果。RY
:選擇一個子序列,將所有R
變為Y
,所有Y
變為R
,B
和空位置不變。RB
:選擇一個子序列,將所有R
變為B
,所有B
變為R
,Y
和空位置不變。YB
:選擇一個子序列,將所有Y
變為B
,所有B
變為Y
,R
和空位置不變。
你需要根據 mix
操作的資訊確定一種可能的原序列。保證 \(n, k \leqslant 10^3\)。
將 WRYB
依次賦值為 \(0, 1, 2, 3\),可以發現 mix
操作即對取出元素做異或。
將 \((00)_2, (01)_2, (10)_2, (11)_2\) 表示為 \((b_ia_i)_2\)。
RY
,交換選定數的 \(a_i, b_i\)。RB
,\(b_i \leftarrow a_i \oplus b_i\)。YB
,\(a_i \leftarrow a_i \oplus b_i\)。
動態維護當前的 \(a_i\) 和 \(b_i\) 與初始值的關係,設 \(i\) 初始為 \((b_0a_0)_2\)。
- \(t_i = (00) \iff a_i = 0\)。
- \(t_i = (01) \iff a_i = a_{i_0}\)。
- \(t_i = (10) \iff a_i = b_{i_0}\)。
- \(t_i = (11) \iff a_i = a_{i_0} \oplus b_{i_0}\)。
\(b_i\) 同理維護一個 \(t_i'\)。
把 \(a_{i_0}\),\(b_{i_0}\) 表示為 \(2n\) 個未知數。
對於一次 mix
操作,可以對分別對當前 \(\{a_i\}\) 和\(\{b_i\}\) 異或得到關於 \(a_{i_0}\),\(b_{i_0}\)的兩組方程。
高斯消元求出所有\(a_{i_0}, \ b_{i_0}\)。
submission
線性基
引入
線性基即高中數學向量基底擴充到 \(n\) 維的情況。
線性基內元素線性無關,即不能互相表示。
線性基可以表示出任意當前線性空間內的元素。
異或線性基
對於一組基 \(\{b\}\),其內元素不能透過異或運算互相表示。
-
高斯消元求線性基
求解 \(\{a\} = {1, 3, 4, 6, 7}\) 的一組基底。
把一個 \(n\) 位二進位制數看作 \(n\) 維向量。
\[\begin{bmatrix} 1 & 0 & 0\\ 1 & 1 & 0\\ 0 & 0 & 1\\ 0 & 1 & 1\\ 0 & 1 & 1\\ \end{bmatrix} \]執行高斯消元。
\[\begin{bmatrix} 1 & 0 & 0\\ 0 & 1 & 0\\ 0 & 0 & 1\\ 0 & 0 & 0\\ 0 & 0 & 0\\ \end{bmatrix} \]剩下 \(3\) 個非零元素 \(\{1, 2, 4\}\)即為 \(\{a\}\) 的一組基。
顯然可用 \(1, 2, 4\) 表示出 \(3, 6, 7\) 卻無法互相表示。
引理:大小為 \(sz\) 的基底能組成 \(2^{sz}\) 個不同的數。
證明:高斯消元得到的基底互不相交,任意組合互不相同。
-
線上求線性基
高斯消元是離線的,複雜且有侷限性。
設 \(b_i\) 為基底中最高位為 \(i\) 的元素。
用如下方法插入新元素,其實際意義與高斯消元無異。
void insert(int x) { for(int i = 30; i >= 0; -- i) { if(x >> i & 1) { if(b[i] == 0) { b[i] = x; return; } x ^= b[i]; } } }
-
求線性基內得到的最大(小)元素
高斯消元得到的基底元素交集為空,全部異或起來即最大值。
線上插入法可以如下貪心:
int get_max() { int cur = 0; for(int i = 30; i >= 0; -- i) { cur = max(cur, cur ^ b[i]); } return cur; }
-
判斷某個元素是否線上性空間記憶體在
低位操作不會影響高位,從高到低貪心。
bool exist(int x) { int cur = 0; for(int i = 30; i >= 0; -- i) { if((x >> i & 1) != (cur >> i & 1)) { cur ^= b[i]; } } return x == cur; }
模板:submission
例題
CF1101G
題意:
給定 \(\{a_i\}\),試將其劃分為儘可能多的非空子段,滿足每一個元素出現且僅出現在其中一個子段中,且在這些子段中任取若干段,它們包含的所有數的異或和不能為\(0\).
如果不存在方案輸出 \(-1\),否則輸出所有合法的劃分方案中最大的劃分數。
表示成字首異或。
設 \(i_1, i_2, \dots i_k\) 為劃分點。
則 \(\{s_{i_2}\oplus s_{i_1 - 1}, \dots s_{i_k}\oplus s_{i_{k - 1} - 1}\}\) 互相組合不能表示出零。
表示出零,當且僅當存在元素能被其他元素表示。
所以 \(\{s_{i_2}\oplus s_{i_1 - 1}, \dots s_{i_k}\oplus s_{i_{k - 1} - 1}\}\) 的線性基(等效於 \(\{s_i\}\) 的線性基)為極大符合條件集合。
線性基的大小唯一確定,無解的情況為 \(s_n = 0\)。
submisson
Reference
OI Wiki
英雄哪裡出來:威爾遜定理 —— 數論四大定理之一
skywalkert:淺談一類積性函式的字首和
《線性代數》(機械工業出版社)