☝️ 서울대학교 권오남 교수님의 [정수론] 강의를 편집한 내용입니다. (링크 클릭 후 가입 시 수강 가능함)
문제 발생 시 삭제될 수 있습니다.
[1] Divisibility, Congruence
(1-1) 정의
-
Divisibility (가분성. 나눌 수 있음)
a, b가 정수일 때, a가 b를 나눈다는 것은 a * k = b가 되는 정수 k가 존재한다는 것이다
a∣b↔∃k,s.t.b=a×k
a≡b(modn)↔n∣(a−b)
(1-2) 정리
아래에서 a, b, c는 모두 정수이고 n은 양의 정수.
- Theorem 1.1 ⭐
(i)a∣b이고 a∣c이면a∣(b+c)이다.(ii)a∣b이고 a∣c이면a∣(b−c)이다. 즉, b≡c(moda)이다.
(i)
a∣b이므로 어떤 정수 k1에 대해 b=ak1이다.
a∣c이므로 어떤 정수 k2에 대해 c=ak2이다.
b+c=(ak1+ak2)=a(k1+k2)이고 (k1+k2) 또한 정수이므로 a∣(b+c)이다.□
(ii)는 (i)과 마찬가지로 증명할 수 있다 □
(i)a≡a(modn)↔ n∣(a−a), n∣0.모든 정수 n이 0을 나누므로 이는 성립함□(ii)a≡b(modn)↔ n∣(a−b)이므로 (a−b)=nk가 되는 어떤 정수 k가 존재.양변에 −1을 곱하면 (b−a)=−nk=(−k)n이 되고,−k 또한 정수이므로n∣(b−a)↔ b≡a(modn). 따라서a≡b(modn)이면b≡a(modn).(iii)a≡b(modn)이므로 n∣(a−b)이고, 따라서 (a−b)=nk1이 되는 정수 k가 존재.b≡c(modn)이므로n∣(b−c)↔∃k2∈Z, s.t.(b−c)=nk2.(a−b)+(b−c)=(a−c)=(nk1+nk2)(a−c)=n(k1+k2),(k1+k2)∈Z이므로 n∣(a−c)↔a≡c(modn)□
(i) a≡b(modn)이고 c≡d(modn)이면 (a±c)≡(b±d)(modn)이다.(ii) a≡b(modn),c≡d(modn)이면ac≡bd(modn)이다.(iii) k>0∈Z에대해,a≡b(modn)이면, ak≡bk(modn)이다.
[2] Greatest Common Divisor
(2-1) 정의
- Common Divisor(공약수) ⭐ 정수 a, b의 공약수 d는 d∣a,d∣b인 정수이다.
- Greatest Common Divisor(최대공약수) ⭐ 정수 a, b의 최대공약수 d는 공약수 중 가장 큰 공약수이다. d = (a, b)로 표기
(2-2) 정리
- Theorem 2.1. ⭐
a,n,b,r,k가정수라고하자.만약a=nb+r이고k∣a,k∣b이면,k∣r이다.
- 증명
k∣a,k∣b이므로a=kc1,b=kc2라고하자.a=nb+r이므로kc1=nkc2+r이고,r=kc1−nkc2=k(c1−nc2)이다.(c1−nc2)=c∗라고할때,c∗∈Z이므로k∣r이다.□
- Theorem 2.2. ⭐
a,b,n,r1가정수라고하자.만약a=nb+r1이면(a,b)=(b,r1)이다.
- 증명
(⊆)(⊇)(∴)C={c∣(c∣a)&(c∣b)},D={d∣(d∣b)&(d∣r)}라고하자.Theorem2.1.에따라C의임의의원소c는d의원소이므로,C⊆D이다.D의임의의원소d에대해,d∣b이고d∣r이다.Theorem1.2에따라d∣b이므로d∣bn1이고Theorem1.1에따라d∣bn1이고d∣r이면d∣bn1+r,즉d∣a이다.D의임의의원소d∈C이므로,D⊆C이다.C⊆D,D⊆C이므로C=D이고,따라서C의최댓값=D의최댓값이다.즉a,b의최대공약수는b,r의최대공약수이다.□
(2-3) Euclidean Algorithm ⭐⭐
Theorem2.2에 따라 정수 a, b의 최대공약수 (a,b)를 구하는 알고리즘이다.
- Q. 그냥 소인수분해 해서 구하면 안되나요? A. 작은 수면 할 수도 있겠지만, 소인수를 구하는 다항식 시간 알고리즘이 아직은(?) 발견되지 못했습니다. [소인수분해] ← 이 문서를 참고.
작은 수면 모르겠지만 큰 수에 대해서는 소인수 분해를 적용하기가 힘든데, 유클리드 알고리즘을 이용하면 확실히 두 수의 최대공약수를 구할 수 있음!
- 유클리드 알고리즘 (설명)
a=bn1+r1이라고하자.(a,b)=(b,r1)이다.b=q2r1+r2라고하자.(b,r1)=(r1,r2)이다.r1=q3r2+r3이라고하자.(r1,r2)=(r2,r3)이다....위작업을rn−1=qn+1rn+rn+1에대해rn+1가0이될때까지반복한다.이때얻을수있는0이아닌가장작은정수rn이바로(a,b)이다.
- 위 알고리즘을 그대로 c++ 코드로 쓰면 다음과 같다
int gcd(int a, int b){
int dividend = a;
int divisor = b;
int quotient;
int remainder;
while (a && b){
quotient = dividend / divisor;
remainder = dividend % divisor;
printf("%d = %d * %d + %d\n", dividend, quotient, divisor, remainder);
if (remainder == 0) return divisor;
dividend = divisor;
divisor = remainder;
}
return -1;
}
int gcd(int a, int b){
if (b == 0) return a;
return gcd(b, a%b);
}
[3] Linear Diophantine Equations & Bezout’s Identity (증명은 나중에…)
(3-1) 정리(1)
- Theorem 3.1.
a,b가정수라고하자.a,b가서로소이다.⟺∃x,y∈Z,s.t.,ax+by=1
- Theorem 3.2. ⭐
0이아닌두정수a,b에대해,다음을만족하는두정수x,y가존재한다.ax+by=(a,b)
- Theorem 3.3. (Euclid’s Lemma)
정수a,b,c에대해,만약a∣bc이고,a와b가서로소이면a∣c이다.
- Theorem 3.4.
a,b,n이정수라하자.a∣n,b∣n,(a,b)=1이면ab∣n이다.
- Theorem 3.5.
(a,n)=1,(b,n)=1이면(ab,n)=1이다.
- Theorem 3.6.
a,b,c,n이정수이고,n>0이라하자.ac≡bc(modn)이고(c,n)=1이면a≡b(modn)이다.
(3-2) 정리(2)
- Theorem 3.7. ⭐
a,b가0이아닌정수이고c가정수이면다음을만족하는정수x,y가존재한다.ax+by=c⟺(a,b)∣c
- Theorem 3.8.
a,b,c,x0,y0이ax0+by0=c인정수라하자x=x0+b/(a,b),y=y0−a/(a,b)인정수x,y또한ax+by=c를만족한다.
- Theorem 3.9.
ax0+by0=c라면,임의의정수k에대해,정수x=x0+kb/(a,b),y=y0−ka/(a,b)또한ax+by=c를만족한다.또한,ax+by=c의모든해들은위와같은형태로나타난다.
(3-3) 확장 유클리드 알고리즘 ⭐
Theorem 3.7.에서 ax+by=c이면 (a,b)∣c임을 보였다.
확장 유클리드 알고리즘은 (a,b)를 구하면서 동시에 ax+by=(a,b)가 되는 정수 x, y를 구하는 알고리즘이다.
유클리드 알고리즘을 다시 살펴보면 다음과 같다.
a=q1b+r1b=q2r1+r2r1=q3r2+r3r2=q4r3+r4...rn−1=qn+1rn+rn+1(rn+1=0,rn=(a,b))
r1=r2=====a−q1bb−q2r1b−q2(a−q1b)b−q2a+q1q2b−q2a+(1+q1q2)b...
이렇게 유클리드 알고리즘에서 보이는 모든 나머지들은 a와 b의 일차결합(ax+by의 꼴)으로 나타낼 수 있다.
이를 일반화해 다음과 같이 표현하자.
ri=sia+tib
여기서 a 를 r−1, b를 r0이라고 하면 다음과 같이 표현할 수 있다.
r−1=1×a+0×br0=0×a+1×b즉,s−1=1,s0=0,t−1=0,t0=1
유클리드 알고리즘에서 rn−1=qn+1rn+rn+1임을 얻었으니, 우리는 다음과 같은 점화식을 얻을 수 있다.
ri+1=si+1a+ti+1b===rn−1−qn+1rnsi−1a+ti−1b−qn+1(sia+tib)(si−1−qn+1si)a+(ti−1−qn+1ti)b∴si+1=si−1−qn+1si,ti+1=ti−1−qn+1ti
우리가 알고 싶은 건 rn=ax+by가 되는 x,y값(즉 sn,tn)이고, 이는 위의 점화식을 이용해 구할 수 있다!
- CODE
pair<pair<int,int>, int> extendedGCD(int a, int b){
int dividend = a, divisor = b;
int quotient, remainder;
int s_prev = 1, s_cur = 0, s_next;
int t_prev = 0, t_cur = 1, t_next;
while (a && b){
quotient = dividend / divisor;
remainder = dividend % divisor;
if (remainder == 0) return {{s_cur, t_cur}, divisor};
s_next = s_prev - quotient * s_cur;
t_next = t_prev - quotient * t_cur;
s_prev = s_cur, s_cur = s_next;
t_prev = t_cur, t_cur = t_next;
dividend = divisor;
divisor = remainder;
}
return {{-1, -1}, -1};
}
끝!