運算思維之 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)?

78
60
39
30
2
3
13
10

\(ans:2×3=6\)

歐幾里得算法

短除法

求 gcd(78, 60)?

78
60
39
30
2
3
13
10

\(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)

3869
6497
1
3869
2628
1
2628
1241
2
2482
146
8
1168
73
2
146
0

\(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)))\)

\approx

\(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