Try   HackMD

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
2020 競技程設教材 HackMD Book
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

2019 Week 14: Number theory

在演算法競賽中,通常涉及的數論大部份是整數代數性質

Modular arithmetic (同餘運算)

在競賽中若計算結果超出了數值範圍外,則通常會要求結果對某個數字取餘數
所以得熟悉取完餘數後的數字們之間的關係運算

練習:

CODEFORCES 1165A Remainder

數字們都對

n 取餘數後,它們就處於"同餘
n
"的狀態下了
a
除以
n
的餘數記做
a (mod n)

記得檢查若 a 為負數的情況

a (mod n)
b (mod n)
相等,則記
ab (mod n)

可將括號內看作數字們處於一個特定狀態下,而同餘通常會省略括號

並且若

abmodncdmodn

a+cb+dmodna×cb×dmodn

練習:

CODEFORCES 1151C Problem for Nazar
CODEFORCES 1165E Two Arrays and Sum of Functions[1]

歐拉定理

如果

a,n 互質,那麼
aϕ(n)1modn

這裡
ϕ(n)
是與
n
互質且小於
n
正整數的個數

例如

1,5
6
互質,
ϕ(6)=2

費馬小定理

如果

a,p 互質,且
p
質數,那麼
ap11modp

是歐拉定理的特例

Greatest Common Divisor

中譯 最大公因數,以下簡稱 GCD
給定整數

a,b,它倆各自有自己的因數[2],取相同的因數中最大的數,即最大公因數
gcd(a,b)

#include<algorithm> 有內建的 __gcd 函數

練習:

CODEFORCES 1155C Alarm Clocks Everywhere
CODEFORCES 1133D Zero Quantity Maximization
CODECHEF SnackDown 2019 Round 1A Chef and Periodic Sequence
CODEFORCES 1107D Compression

GCD 性質

  • gcd(a,b)=gcd(b,a)
  • gcd(a,0)=|a|
  • gcd(a,b)=gcd(a,b%a)

% 是 C++ 中的取餘數運算,表示存在
k
滿足
0b%a=bka<a

Euclidean algorithm

輾轉相除法

給定整數

a,b 求出
gcd(a,b)

a0=a,b0=b,根據 GCD 性質
gcd(a0,b0)=gcd(b0%a0=b1,a0)gcd(b1,a0)=gcd(a0%b1=a1,b1)gcd(a1,b1)=gcd(b1%a1=b2,a1)gcd(ai,bi)=gcd(bi%ai=ai+1,bi)gcd(0,bn)=|bn|

練習:

證明上述過程

gcd參數比參數要先變為
0

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
[3]

綜合上面過程,實作程式碼:

int gcd(int a, int b)
  { return a? gcd(b%a, a) : b; }

練習:

UVa OJ 10407 Simple division

Bezout’s Theorem

對於所有整數

a,b,存在整數
x,y
使得
ax+by=gcd(a,b)

Extended Euclidean algorithm

給定整數

a,b 求出整數
x,y
滿足
ax+by=gcd(a,b)

g=gcd(a,b),配合 Bezout’s Thm 得到:
0xn+gyn=g

明顯的,
xnZ,yn=1

xn 為任意整數

而根據 GCD 性質

gcd(ai,bi)=gcd(bi%ai,ai)
以及
bi%ai=bibiaiai

得到
g=xj(bi%ai)+yjai=xj(bibiaiai)+yjai=xjbi+(yjbiaixj)ai

也就是說

g=aixj1+biyj1 for {xj1=yjbiaixjyj1=xj

綜合上述過程:

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
UVa OJ 10090 Marbles
UVa OJ 10413 Crazy Savages


  1. 請留意 mod 後大小關係會改變QQ ↩︎

  2. 整數

    n因數為可整除
    n
    的數 ↩︎

  3. Wikipedia/ 輾轉相除法的演示動畫 ↩︎