1. 중국인의 나머지 정리(Chinese Remainder Theorem)
정수 m1,m2,...,mn이 임의의 i,j = 1,2,...,n에 대하여 i≠j일때, mi와 mj가 서로소라면, 즉
gcd(mi,mj)=1,i≠j라고 하자.
일차연립합동식 x≡a1(modm1), x≡a2(modm2), x≡a3(modm3), ⋮, x≡an(modmn) 의 해는 mod m1,m2,...,mn에 대하여 유일하게 존재한다.
2. 보조정리 1
정수 a,b,k에 대하여 1−ka×[(ka)−1(modb)]=b×[b−1(moda)]
여기서 [a−1(modm)]은 m에 대한 a의 곱셈의 역원이다.
(증명)
곱셈 역원의 정의는, a×[a−1(modm)]≡1이다.
즉, a와 a의 역원 [a−1(modm)]의 곱을 m으로 나눈 나머지가 1이라는 뜻이다.
그러므로 ka×[(ka)−1modb]≡1은 b에 대하여 적당한 정수 p가 존재하여...
ka×[(ka)−1modb]=bp+1로 바꿔쓸수 있다.
그런데, ka×[(ka)−1modb]은 a로 나눈 나머지가 0이다.
왜냐하면, ka×[(ka)−1modb]는, 정수 k, 정수 a, 정수 [(ka)−1modb]의 곱으로 이루어져 있기 때문에, a로 나누면 당연히 나누어 떨어진다.
그러므로 다음과 같이 a에 대한 합동식으로 바꿔쓸수 있다.
bp+1≡0(moda)
합동식의 성질에 따라 양변에 -1을 빼도 성립하므로,
bp≡−1(moda)
양변에 -1을 곱해도 성립하므로...
b(−p)≡1(moda)
그러므로 -p는 b의 a에 대한 곱셈의 역원 [b−1moda]이고 ka×[(ka)−1modb]=bp+1으로부터 다음 식이 유도된다.
1−ka×[(ka)−1modb]=−bp=b×[b−1moda]
3. 보조정리 2
정수 a,b,m에 대하여...
[a−1modm][b−1modm]=[(ab)−1modm]
(증명)
곱셈 역원의 정의로부터..
a×[a−1modm]≡1(modm)
b×[b−1modm]≡1(modm)
두 식을 곱하면...
ab×[a−1modm][b−1modm]≡1(modm)
그러므로, ab의 m에 대한 곱셈의 역원은... [a−1modm][b−1modm]
4. 중국인의 나머지 정리 해법
두 식 x≡a1(modm1), x≡a2(modm2)을 생각해보자.
먼저 첫번째 식으로부터.. x를 m1으로 나눈 나머지가 a1이므로..
x=m1k1+a1
두번째 식에 대입하면..
m1k1+a1≡a2(modm2)
양변에 a1을 빼면...
m1k1≡(a2−a1)(modm2)
양변에 정수 m1의 m2에 대한 곱셈의 역원을 곱해주면
k1≡[m−11modm2](a2−a1)(modm2)
위 식은 나머지 식이므로, 등식으로 바꾸면 다음과 같다.
k1=m2k2+[m−11modm2](a2−a1)
이 식을 x=m1k1+a1에 대입하면 다음과 같다.
x=m1m2k2+m1[m−11modm2](a2−a1)+a1
식을 풀어써보면 다음과 같다.
x=m1m2k2+a1−a1(m1[m−11modm2])+a2m1[m−11modm2]
보조정리 1 1−ka×[(ka)−1(modb)]=b×[b−1(moda)]에 의하여
x=m1m2k2+a1(m2[m−12modm1])+a2m1[m−11modm2]
이것을 세번째 식인 x≡a3(modm3)에 대입하고 보조정리 2를 이용하면 다음을 얻는다고 한다.
x=m1m2m3k3+m2m3[(m2m3)−1modm1]a1+m3m1[(m3m1)−1modm2]a2+m1m2[(m1m2)−1modm3]a3
n개의 합동식에 대해 위 과정을 반복하면 다음을 얻는다고 한다.
M=m1m2...mn이고 이것을 mi로 나눈 몫 Mi=M/mi라고 하자.
n개의 연립합동식은 다음과 같은 하나의 합동식으로 나타낼 수 있다.
x≡n∑i=1Mi[M−1imodmi]ai(modM)
5. 예시를 통해 이해해보기
x≡5(mod7), x≡13(mod18), x≡21(mod29)의 x를 구해보자.
먼저 m1=7, m2=18, m3=29이고.. 어떤 두 쌍을 잡아도 서로소이다.
(7,18)과 (18,29), (7,29)가 서로소이다.
세 수의 곱 M=7×18×29=3654
그리고 M1=3654/7=522, M2=3654/18=203이고, M3=3654/29=126
그러면 [M−11modm1]을 구해야하는데 어떻게 할 수 있을까
페르마의 소정리로도 구할 수 있고 확장 유클리드 호제법으로도 구할 수 있다.
def extended_gcd(a,b):
before_x = 1
before_y = 0
x = 0
y = 1
while b != 0:
q,r = a//b, a%b
a,b = b,r
before_x,x = x,before_x - x*q
before_y,y = y,before_y - y*q
return a,before_x,before_y
522x≡1(mod7)는 다음과 같이 바꿔쓸수 있다.
522x=7y+1
그러므로, 522x−7y=1
522와 7에 대한 확장 유클리드 알고리즘을 사용하면 x=2를 얻는다.
[M−11modm1]=2
비슷한 방식으로 나머지 M2, M3에 대한 역원은 다음과 같이 구해진다.
[M−12modm2]=11,
[M−13modm3]=3
그러므로 x≡n∑i=1Mi[M−1imodmi]ai(modM)에 대입하면 다음과 같은 하나의 합동식으로 나타난다.
x≡(522∗2∗5+203∗11∗13+126∗3∗21)=42187≡1993(mod3654)
그래서 연립합동식의 해는 정수 k에 대하여..
x=3654k+1993으로 나타낼 수 있다.
6. 2개의 연립합동식의 해
공식을 외우지 못하더라도.. 합동식이 뭔지 알고 있다면 사실 충분히 풀 수 있다.
x≡a1(modm1),
x≡a2(modm2)이라고 하자.
첫번째 합동식은 m1에 대하여... x=m1y+a1인 정수 y가 존재한다.
이를 두번째 합동식에 대입하면... m1y+a1≡a2(modm2)
양변에 a1을 빼면... m1y≡(a2−a1)(modm2)
역시 등식으로 바꾸면.. m1y=m2k+(a2−a1)
그러므로 다음과 같은 선형 디오판토스 방정식으로 바꿀 수 있다.
m1y−m2k=a2−a1
이 선형 디오판토스 방정식의 해법은 다음과 같았다.
먼저 g=gcd(m1,m2)에 대하여, (a2−a1)가 g의 배수가 아니면 해 (y,k)가 존재하지 않는다.
g의 배수라면 (y,k)가 존재하고... 양변을 g로 나눈다.
그러면 m1/g와 m2/g는 서로소이고... (m1/g)y′+(m2/g)k′=1의 해를 확장 유클리드 알고리즘으로 찾는다.
그러한 해 y', k'에 대하여... y = ((a_{2}-a_{1})/g)y', k = -((a_{2}-a_{1})/g)k'을 고르면...
m1y−m2k=a2−a1이 된다.
따라서, y = ((a_{2}-a_{1})/g)y', k = -((a_{2}-a_{1})/g)k'이 하나의 해가 된다.
7. mi의 쌍들이 서로소가 아닐때
위에서 구한 중국인의 나머지 정리의 공식
x≡n∑i=1Mi[M−1imodmi]ai(modM)의 전제조건은, m1,m2,...,mn의 모든 쌍들이 서로소여야 한다.
하지만, 모든 쌍이 서로소인 경우는 극히 드물것이다.
실제로 서로소가 아니더라도, 연립합동식을 하나의 합동식으로 나타낼 수 있다.
바로 위 6번에 기술한대로...
x≡a1(modm1)
x≡a2(modm2)이라고 하자.
첫번째 식은 x를 m1으로 나눈 나머지가 a1이라는 뜻이므로, x=m1k1+a1을 만족하는 정수 k_{1}이 존재한다.
이 식을 두번째 합동식에 넣으면...
m1k1+a1≡a2(modm2)
양변에 a_{1}을 빼면..
m1k1≡a2−a1(modm2)
이러한 합동식을 푸는 방법은 이미 배운적이 있다.
m1k1을 m2로 나눈 나머지가 a_{2} - a_{1}이므로...
m1k1=m2k2+a2−a1
식을 바꿔쓰면..
m1k1−m2k2=a2−a1의 선형 디오판토스 방정식이 된다.
이미 알다시피 m1과 m2의 최대공약수를 g=gcd(m1,m2)라고 하자.
a2−a1이 g의 배수가 아니면, 이 방정식의 해는 존재하지 않는다.
g의 배수라면, 방정식의 해가 존재하고..
구하는 방법은 m1k1−m2k2=a2−a1의 양변을 g로 나누면..
m1g와 m2g는 서로소이고.. 이들을 이용해서 확장 유클리드 알고리즘을 통해 k′1,k′2을 구할 수 있다.
이들은 m1gk′1−m2gk′2=1 의 특수해이다.
그러므로.. m1/g,m2/g를 이용한 확장 유클리드 알고리즘으로 k′1,k′2을 구하자.
만약, k1=a2−a1gk′1, k2=a2−a1gk′2인 k1, k2를 선택하자.
그러면, k′1=ga2−a1k1, k′2=ga2−a1k2이므로,
m1gk′1−m2gk′2=1에 대입하면 다음과 같다.
m1k1−m2k2=a2−a1
그러므로 x=m1k1+a1을 만족하는 x를 찾기 위한 특수해 k1=a2−a1gk′1과 같이 구할 수 있다.
이 식의 일반해는 다음과 같이 구할 수 있다.
m1k1−m2k2=a2−a1에서 m1m2/g를 더하고 빼면..
m1(k1+m2/g)−m2(k2+m1/g)=a2−a1
적당한 정수 p에 대하여... 위 과정을 p번 반복하면
m1(k1+pm2/g)−m2(k2+pm1/g)=a2−a1
그러므로, 일반해는 적당한 정수 p에 대하여.. k1=(a2−a1)gk′1+pm2g
이것을 x=m1k1+a1에 대입하면 다음과 같다.
x=m1(a2−a1)gk′1+pm1m2g+a1
여기서 g=gcd(m1,m2)이므로, m1m2g=lcm(m1,m2)이다.
그러므로 양변을 lcm(m1,m2)로 나누면...
x≡m1(a2−a1)gk′1+a1(mod(lcm(m1,m2)))
만약에 3개 이상의 연립합동식이 존재한다면..
2개씩 합치는 과정을 계속해서 반복하면 된다.
그런데, 합치다가 단 1번이라도 해가 존재하지 않는다면..
즉 a2−a1이 g의 배수가 아니라면... 전체 연립합동식의 해도 존재하지 않는다.
8. 연습문제
23062번: 백남이의 여행 준비의 준비 (acmicpc.net)
23062번: 백남이의 여행 준비의 준비
첫째 줄에 테스트 케이스의 개수 T 가 주어진다. (1≤T≤1,000,000) 각 테스트 데이터는 한 줄로 구성된다. 각 줄에는 여섯 개의 정수 A, B, C, a, b, c 가 주어진다. ($1 \le A,\;B,\;C\le1,000,000
www.acmicpc.net
중국인의 나머지 정리를 사용하는 문제
9. 풀이
결국 다음 연립합동식의 해를 구하면 된다.
x≡a(modA) x≡b(modB) x≡c(modC)
당연하지만 A,B,C가 서로소라는 보장은 없다.
그러므로 2개씩 합쳐서 반복적으로 합쳐나가면 되겠다.
위에서 구한 공식에 맞게 구해
from sys import stdin
#확장 유클리드 알고리즘
def extended_gcd(a,b):
before_x = 1
before_y = 0
x = 0
y = 1
while b != 0:
q,r = a//b, a%b
a,b = b,r
before_x,x = x,before_x-x*q
before_y,y = y,before_y-y*q
return a,before_x,before_y
#유클리드 알고리즘
def gcd(a,b):
while b != 0:
a,b = b,a%b
return a
T = int(stdin.readline())
for _ in range(T):
A,B,C,a,b,c = map(int,stdin.readline().split())
m = [0,A,B,C]
s = [0,a,b,c]
answer = 0
for i in range(1,3):
m_gcd = gcd(m[i],m[i+1])
if (s[i+1] - s[i]) % m_gcd != 0:
answer = -1
break
M_gcd,k1,k2 = extended_gcd(m[i]//m_gcd,m[i+1]//m_gcd)
#서로소가 아닐때, 중국인의 나머지 정리 점화식
s[i+1] = m[i]*(s[i+1]-s[i])*k1//m_gcd + s[i]
m[i+1] = m[i]*m[i+1]//m_gcd
#s[-1]이 음수일수 있어서 최소의 양수로 바꾸는 과정
#나머지연산 1번이면 가능
if answer == 0:
answer = s[-1] % m[-1]
print(answer)
공식에 맞게 반복적으로 합쳐나가는데,
합동식 x≡a(modA)에서 합치고 나서 얻은 a와 A를 저장해나가면 되겠다.
그런데 최종적으로 합치면, 반복문이 끝난건데..
그리고 나서 얻은 합동식은 x≡s[−1](modm[−1])
최소인 자연수 x를 찾아야하는데 그런데, s[-1]이 음수일수 있다.
이걸 양수로 바꾸는 방법은? 먼저 m[-1]을 양수가 될때까지 계속 더해준다.
if answer == 0:
if s[-1] < 0:
k = 1
answer = s[-1]
while answer <= 0:
answer += m[-1]
else:
answer = s[-1]
print(answer)
근데 s[-1]이 우연히 매우 작은 음수 -10000000000000000000000000000000이고 m[-1]이 매우 작은 양수 1이라면..
10000000000000000000000000000000번 더해야 겨우 0이 되는데
여기서 시간이 너무 오래걸린다
그것을 바꾸는 방법은 그냥 나머지 연산 1번만 하면 바로 양수로 바뀐다.
이 나머지 연산 테크닉은 많이 사용한 적이 있지
if answer == 0:
answer = s[-1] % m[-1]
print(answer)
참조
3. 중국인의 나머지 정리 :: rkm0959 (tistory.com)
3. 중국인의 나머지 정리
관련 코드는 github에서 찾아볼 수 있다. 이 주제도 이미 좋은 자료가 있습니다. https://casterian.net/archives/609 사실 3단원까지만 잘 이해해도 CP/PS 하는데는 문제가 없습니다. 레드까지는 문제 없을듯
rkm0959.tistory.com
The Casterian
Home
casterian.net
중국인의 나머지 정리 - 나무위키 (namu.wiki)
중국인의 나머지 정리 - 나무위키
나눗셈 정리에 의하여 m=q⋅lcm(a1,a2,⋯ ,an)+rm=q\cdot\text{lcm}\left(a_1,a_2,\cdots,a_n\right)+rm=q⋅lcm(a1,a2,⋯,an)+r 을 만족하는 정수 q,rq,rq,r이 유일하게 존재한다 (0≤r
namu.wiki
'정수론' 카테고리의 다른 글
팩토리얼(factorial)의 비밀 - 스털링 근사 공식과 자리수 계산하기 (0) | 2023.01.02 |
---|---|
소인수분해 심화응용 - linear sieve와 smallest prime factor 알고리즘 익히기 (0) | 2023.01.02 |
약수의 합과 약수의 개수 공식 익히기 (0) | 2022.12.26 |
컴퓨터가 등비수열의 합을 구하는 방법 (0) | 2022.12.20 |
오일러의 정리를 배우고 거듭제곱의 나머지를 구하는 방법 익히기 (0) | 2022.12.18 |