:+1: [2020 競技程設教材 HackMD Book](https://hackmd.io/@nckuacm/ryLIV6BYI) :+1:
2019 Week 14: Number theory
=
在演算法競賽中,通常涉及的**數論**大部份是**整數**的**代數性質**
# Modular arithmetic (同餘運算)
在競賽中若計算結果超出了數值範圍外,則通常會要求結果對某個數字**取餘數**
所以得熟悉取完餘數後的數字們之間的**關係**及**運算**。
#### 練習:
[CODEFORCES 1165A Remainder](https://codeforces.com/contest/1165/problem/A)
若**數字們**都對 $n$ **取餘數**後,它們就處於"**同餘 $n$**"的狀態下了
將 $a$ 除以 $n$ 的餘數記做 $a \space (\text{mod } n)$
> 記得檢查若 a 為**負數**的情況
若 $a \space (\text{mod } n)$ 與 $b \space (\text{mod } n)$ 相等,則記 $a \equiv b \space (\text{mod } n)$
> 可將括號內看作數字們處於一個特定狀態下,而同餘通常會省略括號
並且若
$$a \equiv b \mod n \\c \equiv d \mod n$$
則
$$a+c \equiv b+d \mod n\\a\times c \equiv b\times d \mod n$$
#### 練習:
[CODEFORCES 1151C Problem for Nazar](https://codeforces.com/contest/1151/problem/C)
[CODEFORCES 1165E Two Arrays and Sum of Functions](https://codeforces.com/contest/1165/problem/E)[^sort]
## 歐拉定理
如果 $a, n$ **互質**,那麼
$$a^{\phi(n)} \equiv 1 \mod n$$
這裡 $\phi(n)$ 是與 $n$ 互質且小於 $n$ 的**正整數**的個數
> 例如 $1, 5$ 和 $6$ 互質, $\phi(6) = 2$
## 費馬小定理
如果 $a, p$ 互質,且 $p$ 為**質數**,那麼
$$a^{p-1} \equiv 1 \mod p$$
> 是歐拉定理的特例
# Greatest Common Divisor
中譯 最大公因數,以下簡稱 GCD
給定整數 $a, b$,它倆各自有**自己的因數**[^factor],取**相同**的因數中**最大**的數,即最大公因數 $\gcd(a, b)$
`#include<algorithm>` 有內建的 `__gcd` 函數
#### 練習:
[CODEFORCES 1155C Alarm Clocks Everywhere](https://codeforces.com/contest/1155/problem/C)
[CODEFORCES 1133D Zero Quantity Maximization](https://codeforces.com/contest/1133/problem/D)
[CODECHEF SnackDown 2019 Round 1A Chef and Periodic Sequence](https://www.codechef.com/problems/PERIODIC)
[CODEFORCES 1107D Compression](https://codeforces.com/contest/1107/problem/D)
### GCD 性質
- $\gcd(a, b) = \gcd(b, a)$
- $\gcd(a, 0) = |a|$
- $\gcd(a, b) = \gcd(a, b \% a)$
> $\%$ 是 C++ 中的取餘數運算,表示存在 $k$ 滿足 $0 \leq b\% a = b - k\cdot a < a$
## Euclidean algorithm
> 輾轉相除法
:::info
給定整數 $a, b$ 求出 $\gcd(a, b)$
:::
令 $a_0=a, b_0=b$,根據 [GCD 性質](#GCD-性質):
$$
\begin{split}
\gcd(a_0, b_0) &= \gcd(b_0 \% a_0 = \underline{b_1}, a_0) \\
\gcd(\underline{b_1}, a_0) &= \gcd(a_0 \% b_1 = \underline{a_1}, b_1) \\
\gcd(\underline{a_1}, b_1) &= \gcd(b_1 \% a_1 = b_2, a_1) \\
&\vdots \\
\gcd(a_i, b_i) &= \gcd(b_i \% a_i = a_{i+1}, b_i) \\
&\vdots \\
\gcd(\mathbf{0}, b_n) &= |b_n|
\end{split}
$$
#### 練習:
:::warning
證明上述過程 $\gcd$ 中**左**參數比**右**參數要先變為 $0$
:::
![](https://i.imgur.com/HtQU22S.gif) [^euclidean]
綜合上面過程,實作程式碼:
```cpp
int gcd(int a, int b)
{ return a? gcd(b%a, a) : b; }
```
#### 練習:
[UVa OJ 10407 Simple division](https://uva.onlinejudge.org/external/104/10407.pdf)
## Bezout’s Theorem
對於所有整數 $a, b$,存在**整數** $x, y$ 使得 $ax + by = \gcd(a, b)$
## Extended Euclidean algorithm
:::info
給定整數 $a, b$ 求出整數 $x, y$ 滿足 $ax + by = \gcd(a, b)$
:::
令 $g = \gcd(a, b)$,配合 [Bezout’s Thm](#Bezout’s-Theorem) 得到:
$$ 0\cdot x_n + g\cdot y_n = g$$
明顯的,$x_n \in \mathbb{Z}, y_n = 1$
> 即 $x_n$ 為任意整數
而根據 [GCD 性質](#GCD-性質) $\gcd(a_i, b_i) = \gcd(b_i\%a_i, a_i)$
以及 $b_i \% a_i = b_i - \lfloor{b_i\over a_i}\rfloor \cdot a_i$
得到
$$
\begin{split}
g &= x_j\cdot (b_i \% a_i) &+ y_j &\cdot a_i \\
&= x_j\cdot (b_i - \lfloor{b_i\over a_i}\rfloor \cdot a_i) &+ y_j &\cdot a_i \\
&= x_j \cdot b_i &+ (y_j - \lfloor{b_i\over a_i}\rfloor \cdot x_j) &\cdot a_i
\end{split}
$$
也就是說
$$
g = a_i \cdot x_{j-1} + b_i \cdot y_{j-1} \text{ for }\begin{cases}
x_{j-1} = y_j - \lfloor{b_i\over a_i}\rfloor \cdot x_j \\
y_{j-1} = x_j
\end{cases}
$$
綜合上述過程:
```cpp
int gcd(int a, int b, int &x, int &y) {
if(!a) {
x = 0, y = 1; // x 為任意整數
return b;
}
int g = gcd(b%a, a, x, y);
int xp = y - b/a * x, yp = x; // p := previous
x = xp, y = yp;
return g;
}
```
#### 練習:
[UVa OJ 10104 Euclid Problem](https://uva.onlinejudge.org/external/101/10104.pdf)
[UVa OJ 10090 Marbles](https://uva.onlinejudge.org/external/100/10090.pdf)
[UVa OJ 10413 Crazy Savages](https://uva.onlinejudge.org/external/104/10413.pdf)
[^factor]: 整數 $n$ 的**因數**為可**整除** $n$ 的數
[^euclidean]: [Wikipedia/ 輾轉相除法的演示動畫](https://zh.wikipedia.org/zh-tw/%E8%BC%BE%E8%BD%89%E7%9B%B8%E9%99%A4%E6%B3%95#/media/File:Euclidean_algorithm_252_105_animation_flipped.gif)
[^sort]: 請留意 mod 後大小關係會改變QQ