Jul. 5 @ 北一女中
講師沒有進過二階 ;-;
很重要所以寫三遍
Number Theory
Combinatorics
Fun Stuff
數論
排列組合
好玩的東西
Number Theory
int gcd(int a, int b) {
return !b ? a : gcd(b, a % b);
// 好耶 一行就寫完了
}
std::gcd(int a, int b); //C++ 17
\(a \equiv b \pmod{m} \iff m | (a - b)\)
mod 12
mod 24
why?
如果AC了就可以拿獎金
\(x \cdot y - N \cdot q = 1\)
\(x \cdot y - N \cdot q = 1\)
\(x \cdot y - N \cdot q = 1\)
\(x \cdot y - N \cdot q = 1\)
int extended_euclidean(int a, int b, int &u, int &v) {
if(!a || !b) {
u = v = 1;
return a ? a : b;
}
int U, V;
int d = extended_euclidean(b % a, a, U, V);
u = U - (b / a) * V;
v = V;
return d;
}
int extended_euclidean(int a, int b, int &u, int &v);
int modular_inverse(int x, int N) {
int y, q;
int d = extended_euclidean(x, N, y, q);
if(d != 1) return 0; // inverse does not exist
return y;
}
歐拉
歐拉歐拉歐拉歐拉
歐拉
歐拉歐拉歐拉歐拉
每 \(p\) 個數字就有一個是 \(p\) 的倍數
Left as exercise ;(
also left as exercise
sorry ;(
\(p = 5: 4^{5} = 1024 \equiv 4 \pmod{5}\)
\(p = 7: 3^{7} = 3^7 = 2187 \equiv 3 \pmod{7}\)
假設:\(p\)為質數,且\(0 < a < p\)。
則:\(1, 2a, 3a, \dots, (p - 1)a\) 為
\(1, 2, 3, \dots, p - 1\) 的重新排列
ex. \(a = 3, p = 5\), 則 \(3, 6, 9, 12 \pmod{5}\) 為 \(3, 1, 4, 2\)
兩邊乘起來:\((p - 1)!a^{p - 1} \equiv (p - 1)! \pmod{p}\)
\(\implies p | \left[(p-1)!\left(a^{p - 1} - 1\right)\right]\)
\(\implies a^{p - 1} \equiv 1 \pmod{p}\)
int modexp(int b, int e, int p) { //b^e (mod p)
int r = 1;
while(e) {
if(e & 1) r = r * b % p;
b = b * b % p;
e >>= 1;
}
return r;
}
int modexp(int b, int e, int p) { //b^e (mod p)
int r = 1;
while(e) {
if(e & 1) r = r * b % p;
b = b * b % p;
e >>= 1;
}
return r;
}
int modular_inverse(int x, int p) {
return modexp(x, p - 2, p);
}
bad word
如果只有一兩個數字, \(N = 10^{12}\) OK
but! 如果想要回答 \(1\) 到\(N\)內有幾個質數就 \(O(N \sqrt{N})\),\(N = 10^6\) 也掰掰了
const int maxN = 1e6 + 10;
isPrime[maxN];
std::vector<int> primes;
void sieve() {
fill(isPrime, isPrime + maxN, true);
for(int i = 1; i < maxN; i++) {
if(i == 1) continue;
if(isPrime[i]) primes.push_back(i);
for(int j = 2 * i; j < maxN; j += i) isPrime[j] = false;
}
}
⋯⋯結果篩出兩條線
const int maxN = 1e6 + 10;
bool isPrime[maxN];
std::vector<int> primes;
void sieve() {
fill(isPrime, isPrime + maxN, true);
for(int i = 2; i < maxN; i++) {
if(isPrime[i]) {
primes.push_back(i);
for(int j = 2 * i; j < maxN; j += i) isPrime[j] = false;
}
}
}
const int maxN = 1e6 + 10;
isPrime[maxN];
std::vector<int> primes;
void sieve() {
fill(isPrime, isPrime + maxN, true);
for(int i = 2; i < maxN; i++) {
if(isPrime[i]) {
primes.push_back(i);
}
for(int p : primes) {
if(i * p >= maxN) break;
isPrime[i * p] = false;
if(!(i % p)) break;
}
}
}
每一個數字 \(n\) 一定有一個最小質因數 \(p^*\)。在 i =
\(n/p^*\) 和 p = \(p^*\) 的時候會被篩掉
const int maxN = 1e6 + 10;
bool isPrime[maxN];
std::vector<int> primes;
int phi[maxN];
void sieve() {
phi[1] = 1;
fill(isPrime, isPrime + maxN, true);
for(int i = 2; i < maxN; i++) {
if(isPrime[i]) {
phi[i] = 1;
primes.push_back(i);
}
for(int p : primes) {
if(i * p >= maxN) break;
isPrime[i * p] = false;
phi[i * p] = phi[i] * phi[p];
if(!(i % p)) {
phi[i * p] = phi[i] * p;
break;
}
}
}
}
\(\phi\) 的乘法規則:
有 \(Q\) 筆詢問,每次都詢問 \(l_i, r_i\)
問 \([l_i, r_i]\) 裡頭有幾個質數?
is useless
資訊培訓還是逃不過文言文的魔爪⋯⋯
「今有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二,問物幾何?」
資訊培訓還是逃不過文言文的魔爪⋯⋯
「今有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二,問物幾何?」
所求 \(x\)
所求 \(x\)
\(x \equiv 2 \pmod{3}\)
\(x \equiv 3 \pmod{5}\)
\(x \equiv 2 \pmod{7}\)
求最小的 \(x\) 使得滿足以下 \(N\) 個條件
\(x \equiv a_1 \pmod{m_1}\)
\(x \equiv a_2 \pmod{m_2}\)
\(\vdots\)
\(x \equiv a_{N - 1} \pmod{m_{N - 1}}\)
\(x \equiv a_N \pmod{m_N}\)
或回傳其無解
問題太難就把問題變簡單!!!
求最小的 \(x\) 使得滿足以下 \(N = 2\) 個條件
\(x \equiv a_1 \pmod{m_1}\)
\(x \equiv a_2 \pmod{m_2}\)
\(x \equiv a_1 \pmod{m_1}\)
\(x \equiv a_2 \pmod{m_2}\)
\(x = m_1q + a_1 = m_2r + a_2\)
\(m_1q - m_2r = (a2 -a_1)\)
\(m_1q - m_2r = (a2 -a_1)\)
擴展歐幾里德!
未知
Q: 以上有解的條件為?
還有其他解嗎?
\(d\not| (a2 - a_1)\)即無解
還有其他解嗎?
如果 \(x\) 是一個解,則\(x \pm k \cdot \textrm{lcm}(m_1, m_2)\) 也是一組解!
不論是模\(m_1\)或\(m_2\)都會被消掉
\(x \equiv a_1 \pmod{m_1}\)
\(x \equiv a_2 \pmod{m_2}\)
\(\vdots\)
\(x \equiv a_{N - 1} \pmod{m_{N - 1}}\)
\(x \equiv a_N \pmod{m_N}\)
\(x \equiv b_1 \pmod{\textrm{lcm}(m_1, m_2)}\)
\(\vdots\)
\(x \equiv a_{N - 1} \pmod{m_{N - 1}}\)
\(x \equiv a_N \pmod{m_N}\)
減少一個式子
不斷套用 \(N = 2\) 最後就可以得到通式了!
\(x = \prod_{i = 1}^{N} \frac{M}{m_i} \cdot \left(\frac{M}{m_i}\right)^{-1}\pmod{m_i}\cdot a_i\)
for(int i = 1; i <= N; i++) {
//N / i is the same for i = i ~ N / (N / i)
//i is the smallest integer k s.t. N/i = N/k
}
const int M = 1e9 + 7, inv2 = 5e8 + 4;
int ans = 0;
for(int i = 1; i <= N; i++) {
//N / i is the same for i = i ~ N / (N / i)
//i is the smallest integer k s.t. N/i = N/k
int l = i, r = N / (N / i)
ans += (((N / i) * (l + r) % M) * (r - l + 1) % M) * inv2 % M;
i = r;
}
Ex. 計算 \(\sum_{i = 1}^{N} i \cdot \lfloor\frac{N}{i}\rfloor\)
(證明略)
\(N\) 以下所有數字的因數數量和為 \(O(N \log N)\)
真的不是廢話啦
真的不是廢話啦
Combinatorics
感謝 IOIC 講義提供例題 :D
請問 \(1\)~\(1000\) 內有幾個數字是 \(2, 3,\) 或 \(5\) 的倍數?
假設有 \(N\) 個集合 \(A = \{A_1, A_2, \dots, A_N\}\)。令 \([N] = \{1, 2, 3, \dots, N\}\),且定義 \(A_J = \cap_{j \in J} A_j\),\(A_{\emptyset} = \cup_{j \in [N]} A_j\)則:
\(\sum_{J \subseteq [N]} |A_J|\cdot(-1)^{|J|} = 0\)
\(N = 2\):\(|A \cup B| - |A| - |B| - |A \cap B| = 0\)
假設有 \(N\) 個集合 \(A = \{A_1, A_2, \dots, A_N\}\)。(通常每一個集合都滿足某個性質),然後妳想要算有幾個元素滿足所有的性質
妳是一個頑皮的郵差,有\(N\)封信,分別對應到\(N\)個家,第 \(i\) 封信就是要給第 \(i\) 個家的。頑皮的妳開始想了:有幾種放信的方法使得每戶人家都有拿到一封信,但是沒有人家拿到自己該拿到的信?請輸出答案 \(\pmod{10^9 + 7}\)。
\(N \le 1000\)
妳是一個頑皮的郵差,有\(N\)封信,分別對應到\(N\)個家,第 \(i\) 封信就是要給第 \(i\) 個家的。頑皮的妳開始想了:有幾種放信的方法使得每戶人家都有拿到一封信,但是沒有人家拿到自己該拿到的信?請輸出答案 \(\pmod{10^9 + 7}\)。
\(N \le 10^5\)
\(f(n) = \sum_{k = 0}^{N} \binom{n}{k} \cdot (n - k)! \cdot (-1)^k\)
選幾個家有被放到對的信,\(O(N \log N)\)
()(())
((()))
()()()
(())()
()(())
((()))
()()()
(())()
可以理解為「觀察無限多次的話會得到的平均值」
一個硬幣有 \(p\) 的機率得到正面、\(1 - p\) 的機率得到反面 —— 連續丟 \(N\) 次硬幣得到的正面次數的期望值為何?
數線上有 \(N = 500\) 個格子,編號由左至右為 \(1\) 到 \(N\)。現在,有一個機器人,他每一單位時間會隨機往左或往右,如果超出範圍就停止了。對於每一個 \(1 \le i \le N\),請輸出如果這個機器人一開始在編號為 \(i\) 的格子的話,它要走到停的時間的期望值為何。
有一棵 \(N \le 10^5 \) 個節點的樹。有一隻馬一開始在節點 \(1\),每一天都會隨機選條還沒走過的邊走,如果沒有的話他就會停;問牠要走的天數的期望值?
Matrix Theory
矩陣可以做加法!兩個矩陣 \(A_{n\times m}, B_{n\times m}\) 的和就只是相對應的元素加起來:
\(\left(\begin{matrix} 1&2&3\\ 4&5&6\end{matrix}\right) + \left(\begin{matrix} 7&8&9\\ 5&8&1\end{matrix}\right) = \left(\begin{matrix} 8&10&12\\ 9&13&7\end{matrix}\right)\)
\(\left(A + B\right)_{ij} = A_{ij} + B_{ij}\)
兩個矩陣 \(A_{n\times m}, B_{m\times k}\) 的乘法就比較複雜了,定義為:
\(\left(A\times B\right)_{ij} = \sum_{x = 1}^{m}A_{ix}B_{xj}\)
且其為一個 \(n \times k\)的矩陣。
\(\left(\begin{matrix} 1&2\\ 3 & 4\end{matrix}\right) \left(\begin{matrix} 4&-2\\-3&1\end{matrix}\right) = \left(\begin{matrix} -2&0\\ 0&-2\end{matrix}\right)\)
其中對角線為\(1\),其餘元素為\(0\)的方陣寫作\(I_{n\times n}\),為乘法單位元。
int GaussianElim(vector<vector<int>> A, vector<int> b, vector<int> &x) {
//returns number of solutions: 0, 1, or 2 if infinite
int N = A.size(), M = A[0].size();
x = vector<int>(M);
vector<int> where = vector<int>(M, -1);
for(int row = 0, col = 0; col < M && row < N; col++) {
int s = row;
for(int i = row; i < N; i++) if(A[i][col]) s = i;
if(!A[s][col]) continue;
where[col] = row;
for(int i = 0; i < M; i++) swap(A[s][i], A[row][i]);
swap(b[s], b[row]);
for(int i = 0; i < N; i++) if(i != row) {
int f = A[i][col] * inv(A[row][col]) % MOD;
for(int j = 0; j < M; j++) {
A[i][j] = sub(A[i][j], A[row][j] * f % MOD);
}
b[i] = sub(b[i], b[row] * f % MOD);
}
row++;
}
for(int i = 0; i < M; i++) if(where[i] != -1) {
x[i] = b[where[i]] * inv(A[where[i]][i]) % MOD;
}
}
最經典的就是費波那契序列:
\(a_1 = a_2 = 1\)
\(a_k = a_{k - 1} + a_{k - 2}\)
要找到第\(N\) 項似乎需要 \(O(N)\) 時間
可以更快嗎?!
其實遞迴關係式可以用矩陣表示!
\(\left(\begin{matrix}a_{n + 1} \\ a_n\end{matrix}\right)= \left(\begin{matrix}1 & 1 \\ 0&1\end{matrix}\right)\left(\begin{matrix}a_{n} \\ a_{n - 1}\end{matrix}\right)\)
\(\left(\begin{matrix}a_{n + 1} \\ a_n\end{matrix}\right)= \left(\begin{matrix}1 & 1 \\ 0&1\end{matrix}\right)^n\left(\begin{matrix}a_{1} \\ a_{0}\end{matrix}\right)\)
用快速幂就可以快速計算矩陣的幂次\(O(k^3 \log N)\) 通常比 \(O(N)\) 好超多 :D
Q&A time