運算思維之 math theory
aka 數論
Lecturer:\(y = tan(\theta) x - \frac{g\;x^2}{2\;{v_0}^2\;sin^2(\theta)}\)
理論上現在是第六堂
1
運算思維之雜七雜八
2
運算思維之數據分析
3
運算思維之三角函數
4
運算思維之排列組合
5
運算思維之向量、矩陣
About Math Theory
聽起來很唬爛
實際上也很唬爛
乍聽之下很簡單,但看到題目不會寫
競程的一大能力,對不起我沒有
運算思維的倒數第二個主題
a month before...
location:建中數學讀書會,你學會了嗎
result:這裡什麼鬼都沒有
ㄟ北一的數學競賽暑訓
有留上課存檔耶
ㄟ這裡有交大競程社
可以讓我蹭耶
Contents
整除
讓我們從最可愛的地方開始
整除
- \(let\;a=bq\),\(a、b、q \in \mathbb{Z}\)
- b 整除 a,或 a 被 b 整除
\(b\;|\;a\)
整除
\(b\;|\;a\)
- 白話文:正負完全不影響整除與否
\(e.g.\)
\(2\;|\;8,(-2)\;|\;8,2\;|\;(-8)\)
- 若 a | b、b | a 同時成立,則 a = \(\pm\;b\)
- 當 ,則 \((-b)\;|\;a\) 、 \(b\;|\;(-a)\) 、 \((-b)\;|\;(-a)\)
整除
已知 \(b\;|\;a\),\(c\;|\;b\),則 \(c\;|\;a\)
\(e.g.\)
\(4\;|\;8,2\;|\;4,由上得\;2\;|\;8\)
\(b\;|\;a,a = b \; q_1\)
\(c\;|\;b,b = c \; q_2\)
\(a=(c\;q_2)\;q_1\),c | a
整除
已知 \(b\;|\;a\),\(let\;m\in\mathbb{Z},b\;|\;ma\)
- 白話文:被除數乘上任一整數,不影響整除與否
- 但滿顯然的,倒過來會爛掉
\(e.g.\)
\(2\;|\;8,2\;|\;16,2\;|\;24\)
整除
令有 \(a_1、a_2、...、a_n\)
\(m_1、m_2、...、m_n\) 等整數
且 b | \(a_1\)、b | \(a_2\)、...、b | \(a_n\)
則 b | \(\Sigma_{i = 1}^n(a_i\,m_i)\)
- 先證明兩項結合就好,後面依此類推
\(a_1=b\,q_1\)
\(a_2=b\,q_2\)
\(m_1\,a_1=b\,q_1\)
\(m_2\,a_2=b\,q_2\)
\(m_1\,a_1+m_2\,a_2\;=\;b\;(q_1\,+\,q_2)\)
\(b\;|\;m_1\,a_1+m_2\,a_2\)
\(e.g.\)
\(2\;|\;4,2\;|\;10\)
\(2\;|\;4×3 + 10×4 = 52\)
整除
已知 \(\frac{2n^3+n^2+13}{n+5}\;\in\;\mathbb{Z}\),求滿足條件的最大整數 n?
- \((n+5)\;|\;(2n^3+n^2+13)\)
根據公式可推得 \(n+5\;|\;s(n+5) + b(n+5)\)
\((2n^3+n^2+13)÷(n+5)=(2n^2+9n-45)\;...\;212\)
- \((n+5)\;|\;(2n^2-9n+45)(n+5)-212\)
- \((n+5)\;|\;-212\) 一定要成立
- \(n = |-212| - 5 = 207\)
\(Ans:207\)
公因數與公倍數
有沒有一種國小的既視感
公因數與公倍數
- 公因數:\(let \; b \; | \; a_1、b \; | \; a_2、...、b \; | \; a_n\)
則稱 b 是 \(a_1、a_2、...、a_n\) 的 公因數,常以 () 表示
- 公倍數:\(let \; a_1 \; | \; b、a_2 \; | \; b、...、a_n \; | \; b\)
則稱 b 是 \(a_1、a_2、...、a_n\) 的 公倍數,常以 [] 表示
- 最大公因數:所有公因數裡最大那一隻,常以 gcd() 表示
- 最小公倍數:所有公倍數裡最小那一隻,常以 lcm() 表示
公因數與公倍數
因為阿蘇很懶所以他不想證明的性質們
排列不影響 ()、[] 的結果
- (a, b, c) = (b, a, c) = (c, a, b) ...
[a, b, c] = [b, a, c] = [c, a, b] ...
- (a, b, c) = (|b|, |a|, |c|)
[a, b, c] = [|b|, |a|, |c|]
別忘了負因數與正因數同時出現
- \(a\,⊥\,b \Longleftrightarrow gcd(a, b) = 1 \Longleftrightarrow lcm(a, b) = a\,b\)
R 他們就互質,不然呢
公因數與公倍數
因為阿蘇很懶所以他不想證明的性質們
- gcd(a, 0) = |a|,\(a \in \mathbb{Z},a \neq 0\)
這個等等會用到ㄛ
- \(\forall k \in \mathbb{Z},(a, b, c) = (a, b, c, k\,a, k\,b, k\,c)\)
畢竟原班人馬還在那邊
跑不掉了
下個性質我必須附證明:(
公因數與公倍數
跑不掉了
下個性質我必須附證明:(
\(a、b \in \mathbb{Z},gcd(a, b) \, lcm(a, b) = a \, b\)
- gcd(a, b) | ab , ab | lcm(a, b)
- \(\frac{a}{gcd(a, b)}、\frac{b}{gcd(a, b)} \in \mathbb{Z},\frac{ab}{gcd(a, b)}是\;a、b\;公倍數\)
- lcm(a, b) | \(\frac{ab}{gcd(a, b)}\),q × lcm(a, b) × gcd(a, b) = ab
- gcd(a, b) × q 必是 a、b 公因數,gcd(a, b) × q | gcd(a, b)
- q | 1,q = 1,gcd(a, b) × lcm(a, b) = a b
公因數與公倍數
\(x、y \in \mathbb{Z},gcd(x, y) = s,lcm(x, y)=t\)
\(xy - 3t - 5s + 8 = 0,求 x、y\)
- \(st - 3t - 5s + 8 = 0\)
- \((s-3)(t-5)+8-15 = 0\)
- \((s-3)(t-5) = 7\)
s - 3 | t - 5 | s | t |
---|---|---|---|
1 | 7 | 4 | 12 |
7 | 1 | 10 | 6 |
-1 | -7 | 2 | -2 |
-7 | -1 | -4 | 4 |
X
X
X
gcd = 4,lcm = 12
\(Ans:(x, y) = (4, 12)\)
歐幾里得算法
aka 輾轉相除法
歐幾里得算法
- 聽說國小有教過...嗎
- 拿來尋找最大公因數,雖然大家都用
短除法
歐幾里得算法
短除法
求 gcd(78, 60)?
\(ans:2×3=6\)
歐幾里得算法
短除法
求 gcd(78, 60)?
\(ans:2×3=6\)
- 如果今天最小的質因數是97?
從 2 往上數會天荒地老
通常都直接放棄
- 如果今天數字超級大,高達幾千萬?
你知道自己最後要把多少數字乘起來
才能得到答案嗎 XD
短除法
歐幾里得算法
- 聽說國小有教過...嗎
- 拿來尋找最大公因數,雖然大家都用
- 這是歐幾里得發現的,
但它跟歐幾里得定理是不同東西
\(gcd(m, n) = gcd(n, r)\)
\(e.g.\)
\(32 = 6×5 + 2\)
\(gcd(32, 6) = 2 = gcd(6, 2)\)
\(m = nq + r\)
基本概念
歐幾里得算法
\(gcd(m, n) = gcd(n, r)\)
\(m = nq + r\)
基本概念
Why?
- 令 \(d\) 是 m、n 的 公因數
- 換言之,m、n 是 d 的 倍數
- \(r = m - nq\)
- 所以 \(r\) 很明顯也會是 \(d\) 的倍數
- 現在把 d 換成 最大公因數 :)
\(d\) 的倍數
而且比較大
\(d\) 的倍數
而且比較小
\(gcd(m, n) = gcd(n, r)\)
\(m = nq + r\)
基本概念
gcd(3869, 6497)
\(6497 = 3869×1 + 2628\)
\(3869 = 2628×1 + 1241\)
\(2628 = 1241×2 + 146\)
\(1241= 146×8 + 73\)
\(146= 73×2 + 0\)
歐幾里得算法
歐幾里得算法
把它用 code 實作出來呢
int gcd (int a, int b){
if (a < b) return gcd(b, a);
/*確保 a 絕對比較大*/
if (b == 0) return a;
/*到底了,a 是最大公因數*/
return gcd(b, a%b);
/*即 m = nq + r 的 n 與 r*/
}
聽起來就很遞迴對吧
歐幾里得算法
複雜度?
- \(n = mq + r\),從 \(m\) 變成 \(r\)
- 過程中最少最少,一定會減少一個 \(m\)
- 承上,最壞狀況下,也能把 \(n\) 剖半
- 以 worst case 考慮,不斷一分為二 ...
O( \(log N\) )
質數
構成整體數論的根本
質數
- 在乘法中,是一個無法再被拆散的單位
- 一般來說,0 與 1 不列入討論範圍內
- 任何一個正合數,都有 唯一 的質因數分解
e.g.
18 = 2 × 3 × 3
42 = 2 × 3 × 7
- 標準分解式:將質因數分解以次方形式表達,升序排列
質數
- 在乘法中,是一個無法再被拆散的單位
- 一般來說,0 與 1 不列入討論範圍內
- 任何一個正合數,都有 唯一 的
e.g.
18 = 2 × 3 × 3
42 = 2 × 3 × 7
標準分解式
- 任何一個正合數,都有 唯一 的 質因數分解
- 標準分解式:將質因數分解以次方形式表達,升序排列
e.g.
\(1224=2^3 × 3^2 × 17\)
e.g.
18 = 2 × 3 × 3
42 = 2 × 3 × 7
質數
- 質數本身有無限多個
證明嗎,不然我們來假設質數是有限ㄉ
這坨質數為 \(p_1、p_2、...、p_n\),其乘積稱為 \(T_1\)
假設存在一自然數 \(T_2 =\Pi_{i=1}^N(p_i)+1\)
每個正合數都有唯一的質因數分解
\(T_2\) 不能被任何一個 \(p_i\) 整除,所以 \(T_2\) 是質數
但 \(T_2 > T_1\) 耶,說好的最大質數是 \(p_n\) 呢
整坨都矛盾,反證法做完ㄌ
質數
尋找質數的方法
窮舉啦哪次不窮舉
嗯哼,然後呢,你要怎麼判斷窮舉出的數字 \(N\),是合數還質數
- 把 \(< N\) 的數字全部拿來除除看?
行,但 O(\(N^2\)),慢到哭
給定一範圍 (1, x],求裡面的所有質數?
- 把 \(< \sqrt{N}\) 的數字全部拿來除除看?
現在是 O(\(N^{\frac{3}{2}}\)),還是有點慢
質數
埃氏篩
- 全名 埃拉托斯特尼篩法,
沒有人在意
- 利用質數的倍數關係排除合數
具體作法
-先假設範圍內全部數字都是質數
-每遇到一個質數,就把它所有倍數都排除在外
-前往下一個數字
質數
埃氏篩
- (推坑)我們來看一下它的 Pseudocode
質數
埃氏篩
- 轉化成 code!
vector <bool> isPrime(MAXN, true);
void solve (){
for (int i = 2; i <= sqrt(MAXN); i++){
if (!isPrime[i]) continue;
for (int j = i*i; j <= MAXN; j += i) isPrime[j] = false;
}
}
- 其實只要枚舉到 \(\sqrt{x}\),就能建完質數表
- 你會發現所有 < \(i^2\) 的 i 倍數都被篩過了,所以從 \(i^2\) 開始就好
質數
埃氏篩
- 複雜度?
那很難算,因為牽扯到一坨積分,我不想講
\(O(N\;log(log(N)))\)
\(O(N)\)
質數
線性篩
- 複雜度是漂亮的 O(N)
保證每個數字都 只會被篩到一次
- 其實跟埃氏篩有點像,但
(100):1、2、4、5、10、20、25、50、100
質數
線性篩
具體作法
-開個東西儲存目前篩出來的所有質數
-同樣從 2 開始往上跑,當跑到數字 \(i\) 時:
從目前篩出來的質數中由小到大遍歷
當遇到質數 \(p\) 時,把 \(i×p\) 排除在外
且若 \(p\;|\;i\),停止遍歷
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
is a prime
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(2×2=4,4\;will\;not\;be\;a\;prime\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2 | 2,break
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
is a prime
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(3×2=6,6\;will\;not\;be\;a\;prime\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(2 \nmid 3,continue\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(3×3=9,9\;will\;not\;be\;a\;prime\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
3 | 3,break
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(×2=8,8\;will\;not\;be\;a\;prime\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2 | 4,break
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
is a prime
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(5×2=10,10\;will\;not\;be\;a\;prime\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(2 \nmid 5,continue\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(5×3=15,15\;will\;not\;be\;a\;prime\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(3 \nmid 5,continue\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(5×5>15,break\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(×2=12,12\;will\;not\;be\;a\;prime\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2 | 6,break
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
is a prime
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(7×2=14,14\;will\;not\;be\;a\;prime\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(2 \nmid 7,continue\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(7×3>15,break\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\(×2 > 15,break\)
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
質數
線性篩
具體作法
vector <bool> isPrime(MAXN, true);
vector <int> prime;
void linear_sieve(){
for (int i = 2; i < N; i++){
if (isPrime[i]) prime.push_back(i);
for (auto to:prime){
if (to * i > N) break;
isPrime[i*to] = false;
if (i % to == 0) break;
}
}
}
工作區
prime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
接著你就會發現有人動畫做到不耐煩了
質數
線性篩
所以這坨奇怪作法的核心概念是什麼?
- 令自然數 N 的唯一質因數分解為 \(a×b×c×d\)
- 而我們希望,N 只被 \((b×c×d)\) 篩到
e.g.
理論上,24 = 2 × 2 × 2 × 3,只會被 12 篩到
若我們在做 8 時,發現 2 | 8 卻沒 break
硬要做 8 × 3 = 24 的話,24 就會被篩到 2 次
質數
- 線性篩一定比埃氏篩快嗎?
還要算上常數,複雜度並非唯一判斷
而且 log(log(N)) 在 N 夠小的情況下真的沒影響
@ MAXN \(\leq 2×10^8\):
埃氏篩 > 線性篩
@ MAXN \(> 2×10^8\):
線性篩 > 埃氏篩,約快個 10% 左右
- 若只是幾筆判斷,直接硬做就好了,不見得要建立整張質數表
- 篩法 DP:能拿來找質因數,有興趣可以自己查
同餘
陳亮延的考幹試教
同餘
由於答案的數字可能很大,請將其模 1e9 + 7 後輸出
由上可知:
- 質數真的很重要,你看 1e9 + 7 出來了吧
- 這題肯定很噁心
- 不用開 long long,好誒
- 如果你是用以下方法做的,通常會吃 WA
cout << ans%MOD << '\n';
同餘
But Before That...
你真的知道數學上的 模 是什麼嗎?
- 0,他絕對不是唸 趴。正式的名稱是 mod
- ≡,這個東西,LaTeX 裡面的 \equiv
- 可以代表 若且唯若,雖然我推薦用 \(\iff\)
- 可以代表 兩邊敘述式恆等
- 也可以代表 同餘
所以我要怎麼表達 17 % 5 = 2 這種東西
同餘
所以我要怎麼表達 17 % 5 = 2 這種東西
\(17 \equiv 2\pmod{5}\)
17 與 2 在 mod 5 的情況下,餘數相同
- 17 ÷ 5 = 3 ... 2,17 mod 5 = 2
- 2 ÷ 5 = 0 ... 2,2 mod 5 = 2
- \(a \equiv b\pmod{n}\) 等同於 \(n\mid(a-b)\)
e.g.
\(23 \equiv 2 \pmod{7}\),\(7 \mid (23-2)\)
同餘
- 對稱性:已知 \(a \equiv b \pmod{n}\),則 \(b \equiv a \pmod{n}\)
e.g.
\(19 \equiv 3 \pmod{4}\),\(3 \equiv 19 \pmod{4}\)
這應該不用證明吧
- 傳遞性:已知 \(a \equiv b \pmod{n}\)、 \(b \equiv c \pmod{n}\) ,則 \(a \equiv c \pmod{n}\)
e.g.
\(11 \equiv 5 \pmod{6},5 \equiv 1 \pmod{2}\)
\(11 \equiv 1 \pmod{2}\)
同餘
- 傳遞性:已知 \(a \equiv b \pmod{n}\)、 \(b \equiv c \pmod{n}\) ,則 \(a \equiv c \pmod{n}\)
-把 mod 轉換一下
n | (a-b)、n | (b-c)
-利用整除公式合併他們
n | (a-b) + (b-c)
n | (a-c)
-再還原回來
\(a \equiv c \pmod{n}\)
同餘
e.g.
\(12 \equiv 2 \pmod{5}、13 \equiv 3 \pmod{5}\) ,則 \(25 \equiv 5 \pmod{5}\)
\(25 \equiv 0 \pmod{5},5 \mid 25\)
- 相加公式:當 \(a \equiv b \pmod{k}、c \equiv d \pmod{k}\) 成立,
則 \((a+b) \equiv (c+d) \pmod{k}\)
- 工程師比較喜歡的版本:
(a+b) % k = [ (a%k) + (b%k) ] % k
同餘
- 相加公式:當 \(a \equiv b \pmod{k}、c \equiv d \pmod{k}\) 成立,
則 \((a+c) \equiv (b+d) \pmod{k}\)
(a+b) % k = [ (a%k) + (b%k) ] % k
k | (a+c) - (b+d)
-老樣子,轉換
k | (a-b)、k | (c-d)
-其實跟剛剛有 87% 像
k | (a-b) + (c-d)
-還原
\((a+c) \equiv (b+d) \pmod{k}\)
同餘
- 相減公式:當 \(a \equiv b \pmod{k}、c \equiv d \pmod{k}\) 成立,
則 \((a-c) \equiv (b-d) \pmod{k}\)
(a-b) % k = [ (a%k) - (b%k) ] % k
拜託啦,我真的懶得寫這個證明了
打 LaTeX 很累ㄟ
你就把剛剛的加號變成減號就好了
:pleading_face:
噢不,你也沒有拒絕的權利
同餘
- 相乘公式:當 \(a \equiv b \pmod{k}、c \equiv d \pmod{k}\) 成立,
則 \(ac \equiv bd \pmod{k}\)
ab % k = [ (a%k) (b%k) ] % k
拜託啦,我真的...
好咩,我寫就是了
e.g.
\(12 \equiv 2 \pmod{5}、13 \equiv 3 \pmod{5}\) ,則 \(156 \equiv 6 \pmod{5}\)
\(156 \equiv 1 \pmod{5}\)
同餘
- 相乘公式:當 \(a \equiv b \pmod{k}、c \equiv d \pmod{k}\) 成立,
則 \(ac \equiv bd \pmod{k}\)
ab % k = [ (a%k) (b%k) ] % k
好咩,我寫就是了
- 就算這裡只是一坨幹話,你也知道我做了什麼
k | (a-b)、k | (c-d)
- 那如果我偷偷在前面乘上 c,後面乘上 b 呢?
k | c(a-b)、k | b(c-d)
k | ca - cb、k | bc - bd
同餘
- 相乘公式:當 \(a \equiv b \pmod{k}、c \equiv d \pmod{k}\) 成立,
則 \(ac \equiv bd \pmod{k}\)
ab % k = [ (a%k) (b%k) ] % k
- 那如果我偷偷在前面乘上 c,後面乘上 b 呢?
k | c(a-b)、k | b(c-d)
k | ca - cb、k | bc - bd
- 答對ㄌ,兩式相加
k | ca - bd
- 然後呢?就還原 R,不然你想幹嘛
\(ac \equiv bd \pmod{k}\)
同餘
- 次方公式:已知 \(a \equiv b \pmod{k}\)
,則 \(a^c \equiv b^c \pmod{k}\)
自己延伸相乘公式的證明啦
現在半夜 3. 了 இ௰இ
\(a \equiv b \pmod{k}\) 乘上自己 c 次,很簡單吧
同餘
- 倍數公式:已知 \(a \equiv b \pmod{k}\)
,則 \(ac \equiv bc \pmod{k}\)
k | ca - cb
-我連幹話都懶得掰了
k | (a-b)
-你為什麼要浪費時間讀這段文字
k | c(a-b)
-ㄟ你知道嗎,我今天早上喝了兩杯咖啡,比平常多一杯
\(ac \equiv bc \pmod{k}\)
同餘
加法 | (a+b) % k= [ (a%k) + (b%k) ]%k |
---|---|
減法 | (a-b) % k= [ (a%k) - (b%k) ]%k |
乘法 | ab % k= [ (a%k) (b%k) ]%k |
好,讓我們先 focus 在工程師公式(?)就好
cout << ans%MOD << '\n';
回歸問題,為何這麼做會吃 WA
人家就跟你說答案會很大,所以才要模數字
如果答案能讓你放在 ans 中,幹嘛多此一舉
所以你 ans 早就爆掉了 (*゜ー゜*)
同餘
加法 | (a+b) % k= [ (a%k) + (b%k) ]%k |
---|---|
減法 | (a-b) % k= [ (a%k) - (b%k) ]%k |
乘法 | ab % k= [ (a%k) (b%k) ]%k |
好,讓我們先 focus 在工程師公式(?)就好
- 是故,請在計算過程中,就先完成模的動作
- 強烈推薦寫成一個模板,直接套來用
#define ll long long int
const int MOD = 1e9 + 7;
ll Mod (ll a, int m = MOD){
return (a+m) % m;
}
ll Plus (ll a, ll b, int m = MOD){
return ((a%m) + (b%m))%m;
}
ll Minus (ll a, ll b, int m = MOD){
return ((a%m) - (b%m))%m;
}
ll Mult (ll a, ll b, int m = MOD){
return ((a%m) * (b%m))%m;
}
同餘
話說,除法呢,我可以用乘法反元素的邏輯去做嗎
顯然否。會爛得一蹋糊塗,跟我物理一樣
- 模本身是個 整數剩餘系(等等會講到),我們 無法保證除法出來會是整數
- 若真的要做除法,應該乘上 模反元素,aka 逆模元
其實這本是今日範圍,但我發現講了這個
你們 21:00 前估計出不了電教了,所以留給演算法ㄅ
\(48 \equiv 3 \pmod{5},12 \equiv 2 \pmod{5}\)
\(4 \equiv \frac{3}{2} \pmod{5}\)?????
歐拉函數
歐拉是個很討人厭的傢伙
尤其是跟數學或自然有關的時候
歐拉函數
- 以希臘字母 \(\phi()\) 表示,如果你忘記,那個是小寫 [phi]
- 很明顯的,對於質數 p 來說,\(\phi(p)=p-1\)
- 再繼續講下去之前,我們得先做一些
名詞介紹
- 定義 \(\phi(n)\) 為符合 \(\leq n,gcd(i, n)=1\) 的數字總量
e.g.
\((10) = 1、2、5、10,\phi(10) = 3\)
\((17) = 1、17,\phi(17) = 16\)
歐拉函數
名詞介紹
- 完全剩餘系
-一個大小為 n 的集合
-裡面的每個元素拿去 \(mod\;n\) 後,會得到相異 n 個元素
-翻譯年糕:for (int i = 0; i < n; i++),集合裡裝著 \(i + qn\)
e.g.
n = 7:{ 0, 1, 2, 3, 4, 5, 6 }
n = 9:{ 9, 10, 11, 12, 13, 14, 15, 16, 17 }
歐拉函數
名詞介紹
- 非負最小完全剩餘系
-字面上的意思
-翻譯年糕:裝著 0 ~ n-1 的 set
e.g.
n = 5:{ 0, 1, 2, 3, 4, 5 }
n = 8:{ 0, 1, 2, 3, 4, 5, 6, 7, 8 }
歐拉函數
名詞介紹
- 簡化剩餘系
-只留下完全剩餘系中,與 n 互質的數
-翻譯年糕:
e.g.
n = 7:{ 1, 2, 3, 4, 5, 6 }
n = 8:{ 1, 11, 13, 15 }
for (int i = 0; i < n; i++)
if (gcd(i, n) = 1)
vec.push_back(i);
歐拉函數
名詞介紹
- 非負最小簡化剩餘系
-字面上的意思
-翻譯年糕: 的定義就是它的大小
e.g.
n = 11:{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
n = 8:{ 1, 11, 13, 15 }
歐拉函數
歐拉函數
歐拉函數
然後呢,我們要怎麼求
- 令 \(N\) 的標準分解式為 \({p_1}^{k_1}×{p_2}^{k_2}×...×{p_n}^{k_n}\)
則 \(\phi(N)=N\;\Pi_{i=1}^{n}(1 - \frac{1}{p_i})\)
\(e.g.\)
\(12 = 2^2×3\)
\(=12×\frac{1}{2}×\frac{2}{3}=4\)
\(\phi(12)=12×(1-\frac{1}{2})×(1-\frac{1}{3})\)
12 的非負最小簡化剩餘系:{ 1, 5, 7, 11 }
\(\phi(12)=4\)
歐拉函數
歐拉函數
然後呢,我們要怎麼求
- 令 \(N\) 的標準分解式為 \({p_1}^{k_1}×{p_2}^{k_2}×...×{p_n}^{k_n}\)
則 \(\phi(N)=N\;\Pi_{i=1}^{n}(1 - \frac{1}{p_i})\)
證明ㄛ,Hmm ...
有個東西叫 中國剩餘定理
我們有教過嗎?沒有
我們今天會教嗎?不會
所以我們就跳過證明吧
- 是的沒錯,並不會受到次方影響
歐拉函數
- 歐拉函數具有此性質:\(n = \Sigma_{d \mid n}(\phi(d))\)
- 翻譯:n 所有因數的 \(\phi()\) 加起來,剛好會等於 n
\(e.g.\)
(18) = 1, 2, 3, 6, 9, 18
i | φ(i) |
---|---|
1 | 1 |
2 | 1 |
3 | 2 |
6 | 2 |
9 | 6 |
18 | 6 |
\(1+1+2+2+6+6=18\)
歐拉函數
- 歐拉函數具有此性質:\(n = \Sigma_{d \mid n}(\phi(d))\)
- 翻譯:n 所有因數的 \(\phi()\) 加起來,剛好會等於 n
- 稍微移項一下,\(\phi(n) = n - \Sigma_{d \mid n, d < n}\;(\phi(d))\)
\(e.g.\)
\(\phi(18)=18-\phi(1)-\phi(2)-\phi(3)-\phi(6)-\phi(12)\)
\(= 18 - 1 - 1 - 2 - 2 - 6 = 6\)
歐拉函數
給定一範圍 (1, x],Q 筆詢問而且 Q 夠大
每筆詢問輸入一個 n,試問 \(\phi(n)\)?
- 求出單個數字的 \(\phi()\):
利用第一個公式,只要列舉出質因數就能計算
O(\(\sqrt{n}\))
- 求出整個範圍呢?
O(\(n^{\frac{3}{2}}\))
對,沒錯,有夠慢、超級慢
歐拉函數
給定一範圍 (1, x],Q 筆詢問而且 Q 夠大
每筆詢問輸入一個 n,試問 \(\phi(n)\)?
- 利用第二個公式
O\((n\,log\, n)\)
從小數字開始往上列舉倍數,把它扣掉自己的 \(\phi()\)
void sieve (int N){
for (int i = 1; i <= N; i++) phi[i] = i;
for (int i = 1; i <= N; i++)
for (int j = 2*i; j <= N; j += i)
phi[j] -= phi[i];
}
歐拉函數
給定一範圍 (1, x],Q 筆詢問而且 Q 夠大
每筆詢問輸入一個 n,試問 \(\phi(n)\)?
- 再優化
做完埃氏或線性篩後
對每個數用篩法 DP 質因數分解
再利用公式來 O(1) 解出歐拉函數
是ㄉ,這並非今日範圍,我沒有要教
歐拉定理
費馬小定理
Last but not least
歐拉定理
- 其實同名的定理滿多的,如果你直接查:
- 別名 費馬-歐拉定理 or 歐拉 \(\phi\) 函數定理,順帶一提有人會把歐拉翻成尤拉
歐拉定理
- 直接切入主題的話:
\(e.g.\)
if gcd(m, n) = 1
than \(m^{\phi(n)} \equiv 1 \pmod{n}\)
\(m^{\phi(n)} \equiv 1 \pmod{n}\)
We know that gcd(3, 8) = 1
m = 3,n = 8,\(\phi(8) = 4\)
\(3^{\phi(8)} \equiv 1 \pmod{8}\)
\(3^{4} \equiv 1 \pmod{8}\)
\(81 \equiv 1 \pmod{8}\)
歐拉定理
if gcd(m, n) = 1
than \(m^{\phi(n)} \equiv 1 \pmod{n}\)
放心啦這個我會寫證明
- n 的 非負最小簡化剩餘系 大小?
\(\phi(n)\)
- 我們假設它是集合 N ,等同於{\(a_1, a_2, ..., a_{\phi(n)}\)}
- 選出一個與 n 互質的數 m,可以看出:
\((m\,a_i)\;mod\;n\) 之值皆不相同
而且遍歷過 N 後
這坨值又會形成 n 的非負最小簡化剩餘系
歐拉定理
if gcd(m, n) = 1
than \(m^{\phi(n)} \equiv 1 \pmod{n}\)
8 的 非負最小簡化剩餘系:{ 1, 3, 5, 7 }
m = 3,n = 8,\(\phi(8) = 4\)
\((3×1)\;mod\;8=3\)
\((3×3)\;mod\;8=1\)
\((3×5)\;mod\;8=7\)
\((3×7)\;mod\;8=5\)
\((m\,a_i)\;mod\;n\)
歐拉定理
if gcd(m, n) = 1
than \(m^{\phi(n)} \equiv 1 \pmod{n}\)
- 這可能有點抽象,我等等會上例子:根據相乘公式,把所有式子相乘
\((m\,a_1)(m\,a_2)...(m\,a_{\phi(n)}) \equiv a_1\,a_2\,...\,a_{\phi{n}} \pmod{n}\)
※ a 的編號是唬爛的
總之就是非負最小簡化剩餘系的其中一個元素
\(\Pi_{i = 1}^{\phi(n)}(a_i)×m^{\phi(n)} \equiv \Pi_{i=1}^{\phi(n)} \pmod{n}\)
歐拉定理
if gcd(m, n) = 1
than \(m^{\phi(n)} \equiv 1 \pmod{n}\)
- 這可能有點抽象,我等等會上例子:根據相乘公式,把所有式子相乘
\(\Pi_{i = 1}^{\phi(n)}(a_i)×m^{\phi(n)} \equiv \Pi_{i=1}^{\phi(n)} \pmod{n}\)
- 左右式同時消去 \(\Pi_{i=1}^{\phi(n)}\)
\(m^{\phi(n)} \equiv1 \pmod{n}\)
歐拉定理
if gcd(m, n) = 1
than \(m^{\phi(n)} \equiv 1 \pmod{n}\)
m = 3,n = 8,\(\phi(8) = 4\)
\((3×1)\;mod\;8=3\)
\((3×3)\;mod\;8=1\)
\((3×5)\;mod\;8=7\)
\((3×7)\;mod\;8=5\)
\((3×1) \equiv 3 \pmod{8}\)
\((3×3) \equiv 1 \pmod{8}\)
\((3×5) \equiv 7 \pmod{8}\)
\((3×7) \equiv 5 \pmod{8}\)
\((3×1)(3×3)(3×5)(3×7) \equiv 3×1×7×5 \pmod{8}\)
\(3^4(1×3×5×7) \equiv (3×1×7×5) \pmod{8}\)
歐拉定理
if gcd(m, n) = 1
than \(m^{\phi(n)} \equiv 1 \pmod{n}\)
m = 3,n = 8,\(\phi(8) = 4\)
\(3^4(1×3×5×7) \equiv (3×1×7×5) \pmod{8}\)
\(3^4 \equiv 1 \pmod{8}\)
費馬小定理
- 歐拉定理中的特例,但邏輯完全相同
in other words, \(m^{n} \equiv m \pmod{n}\)
if [gcd(m, n) = 1] \(\wedge\) [n is a prime]
than \(m^{n-1} \equiv 1 \pmod{n}\)
\(e.g.\)
We know that 5 is a prime,gcd (3, 5) = 1
m = 3,n = 5,\(\phi(n) = 4\)
\(m^{n-1} \equiv 1 \pmod{n}\)
\(3^{4} \equiv 1 \pmod{5}\)
\(81 \equiv 1 \pmod{5}\)
費馬小定理
in other words, \(m^{n} \equiv m \pmod{n}\)
if [gcd(m, n) = 1] \(\wedge\) [n is a prime]
than \(m^{n-1} \equiv 1 \pmod{n}\)
- 證明真的很鳥,援引歐拉定理:\(m^{\phi(n)} \equiv 1 \pmod{n}\) if gcd(m, n) = 1
- 質數 p 的 \(\phi()\) 等於多少?
p-1
費馬小定理
in other words, \(m^{n} \equiv m \pmod{n}\)
if [gcd(m, n) = 1] \(\wedge\) [n is a prime]
than \(m^{n-1} \equiv 1 \pmod{n}\)
- 證明真的很鳥,援引歐拉定理:\(m^{\phi(n)} \equiv 1 \pmod{n}\) if gcd(m, n) = 1
- 質數 p 的 \(\phi()\) 等於多少?
p-1
- 直接帶入進去,\(\phi(n)=n-1\)
- 你問我最下面那行的來源?就兩邊同乘一個 m 啊
歐拉定理、費馬小定理
- 其實歐拉定理可以再延伸下去,變成
廣義歐拉定理
歐拉定理、費馬小定理
廣義歐拉定理
- 可以拿來做模除的降冪
- 你以為我要講嗎,
並沒有
廣義歐拉定理
歐拉定理、費馬小定理
- 其實歐拉定理可以再延伸下去,變成
- 歐拉定理通常會被拿來找 模反元素
對,我還是沒有要講,你想多了
- 不過有個概念可以先有就是,
如果我要將同餘定理推廣到除法
則我必須保證除的數 m 與模的數 n 互質
- 所以我們會想辦法對 m 做一些操作,此由 歐拉定理 或 擴展歐幾里得算法
可得
古之寒假必有活。
寒假者,所以資飯睡覺打冬冬也。
人非孤而得樂者,孰能不報?
知而不報名,再無機會,終留憾也。
建電學長,其報寒訓固先乎吾,吾從而習之;
北資學姊,其報寒訓亦先乎吾,吾從而習之。
寒訓者也, 豈因其先後而不得樂乎?
是故無論建北,無長無少,寒訓所存,樂之所存也。
寒訓報名截止最後一個禮拜,快點來報啦QAQ