Extended Euclid, Chinese Remainder
참고Permalink
Euclidean algorithmPermalink
코드Permalink
int gcd(int m, int n) // m >= n 를 만족해야함
{
int z, a, b;
a = m, b = n;
while (b)
{
z = a%b;
a = b; b = z;
}
return a;
}
설명Permalink
최대공약수(GCD) 구하는 알고리즘임.
나눗셈 정리 를 이용하면
- b 의 약수는
의 약수기도 하므로 와 b 의 약수의 최대공약수를 구해도 됨.
이때 시간복잡도는
이므로 이 성립하므로- 2번 재귀마다 계산되는 두 항은 적어도 반토막 나기 때문임.
Bezout’s IdentityPermalink
if
then there exists integers x and y such that
주의해야할 점은 x, y 가 정수이지 자연수가 아니라는 것.
Extended Euclidean AlgorithmPermalink
Bezout’s Identity 의 해를 구하기Permalink
즉 ax + by = d 에서 x, y 구하기가 확장 유클리드 호제법의 목표임.
유클리드 호제법의 점화식을 변형해서 증명함.
그리고, 어떤 식
따라서
그럼
가 임의의 수 s, t, q 에 대해서 만족하는걸 이용해서
그럼 r, s, t 를 구하는 식이 q 에 대해서 비슷한 모양의 점화식인 것을 확인할 수 있음.
따라서 유클리드 호제법을 쓰면서 r, q, s, t 를 업데이트 하다가 r 이 GCD(a, b) 가 되었을 때의 s, t 를 가져오면 그게 바로 배주 항등식의 해임
코드Permalink
void EEA(int a, int b, int& s, int& t) // a > b 임
{
int r0 = a, r1 = b, s0 = 1, s1 = 0, t0 = 0, t1 = 1;
int tmp = 0, q = 0;
while (r1) {
q = r0 / r1;
tmp = r0;
r0 = r1; r1 = tmp - r1 * q;
tmp = s0;
s0 = s1; s1 = tmp - s1 * q;
tmp = t0;
t0 = t1; t1 = tmp - t1 * q;
}
s = s0; t = t0;
}
응용Permalink
, 혹은 부호 바꿔서 해도 같은 결과가 나옴.- 왜냐면
는 최소공약수이기 때문임. - 즉
의 임의의 배수만큼 구해진 와 의 거리를 별려도 된다는 것. - 그러므로
를 하면 상수시간 안에 원하는 해를 구할 수 있음
- 왜냐면
- 임의의 값
에 대해 로 간단히 확장가능함 이기 때문임.- 단
는 의 자연수배여야함 가 최소공약수이기 때문에 가능한 모든 를 커버할 수 있음.
위 두 이유 때문에 Bezout’s Identity 의 해가 많이 사용됨.
Chinese Remainder Theorem(CRT)Permalink
쌍마다 서로소인 정수집합
에 대해 연립방정식 는 유일한 해를 가진다.
증명Permalink
UniquenessPermalink
방법은 간단한데
그러면
따라서
ExistencePermalink
-
Non-Contructive
나눗셈 정리
은 존재하고 하나 존재함.그리고 이게
와 오직 하나와 대응 함을 위에서 밝힘그래서 존재함.
-
Constructive
case 가 2개일 때 우선 살펴봄.
이라고하면 Bezout’s Identity 에 따라서
를 만족하는 정수 , 가 존재함.위 식에
로 모듈러를 취하면 이고 에 대해서도 비슷하게 할 수 있음.그러면
에 대해서 과 로 모듈러를 취했을 때 각각 , 가 나오면 이러한 가 어떤 수인지 구성한 것임. 을 만족하고 비슷하게 임을 확인할 수 있음.그러므로 위
가 가능한 해 중 하나임.case 가 3개 이상인 경우도 비슷하게 하면 됨.
코드Permalink
int main()
{
int t, m, n, x, y;
int a, b, r, tmp;
cin >> t;
while (t--)
{
cin >> m >> n >> x >> y;
x--; y--;
r = GCD(m, n);
if ((y - x) % r) { // 최소공약수를 주기로 돌기때문
cout << -1 << '\n';
continue;
}
int64_t cop_m = m / r;
int64_t cop_n = n / r;
int64_t r1 = x % cop_m; // CRT 적용을 위해 서로소로 만듬
int64_t r2 = y % cop_n;
int64_t cycle = cop_m * cop_n;
EEA(cop_m, cop_n, a, b);
int64_t tmp = r2 * cop_m * a + r1 * cop_n * b;
tmp %= cycle; // m, n 을 서로소로 만든 후 x 를 구하고
if (tmp < 0) tmp += cycle; // 베주 항등식으론 음수도 나오므로 양수로 바꿈
for(int i = 0 ; i < r; i++, tmp += cycle) // cop_m, cop_n 의 공배수를 더해도 주어진 조건을 만족함
if (tmp % m == x && tmp % n == y) {
cout << tmp + 1 << '\n';
break;
}
}
}
댓글남기기