The Way
백준 11661번: 해의 개수 본문
자기 전에 한 문제만 풀고 자려고 했는데, 이 문제 때문에 잠을 못잤다. 케이스가 상당히 극악인 문제이다.
문제는 아주 심플하다. 방정식 Ax + By + C = 0의 정수해의 개수 구하기이다.
x와 y는 x1 ≤ x ≤ x2, y1 ≤ y ≤ y2를 만족해야 한다.
각 수의 범위는 -10^8 ~ 10^8이다.
일단 수의 범위가 상당히 크기 때문에 직접 다 해보는 알고리즘은 시간초과가 뜰 가능성이 농후하다.
케이스를 나누어가며 접근해보자.
i) A와 B 둘 다 0인 경우
가장 쉬운 경우이다. C = 0이면 모든 해가 정답이고, C ≠ 0이면 해가 없다.
ii) A와 B 둘 중 하나만 0인 경우
편의상 A = 0, B ≠ 0이라 해보자.
그럴 경우 방정식은 By + C = 0이 된다. C가 B로 나누어 떨어지고, 그 해가 y1 ≤ y ≤ y2을 만족할 경우 해가 존재하며, 이 때 x는 어떤 수가 와도 된다.
iii) A와 B 둘 다 0이 아닌 경우
대망의 케이스이다.
이를 풀기 위해서는 약간의 정수론적 배경지식이 필요하다.
먼저, ax + by = c가 정수해 (x, y)를 가지려면 gcd(a, b) | c를 만족해야 한다. 만족하지 않으면 해가 존재하지 않는다.
만족하는 경우에는 어떻게 풀어야 할까?
gcd(a, b) = d라 하자. 그러면 a = da', b = db'로 나타낼 수 있다.
이 경우, 만약 하나의 해 (x0, y0)를 찾아낼 수 있다면 모든 해는 다음과 같은 꼴로 나타낼 수 있다.
x = x0 + b'k, y = y0 - a'k (k는 임의의 정수)
그렇다면 관건은, 하나의 해 (x0, y0)를 찾아내는 것이다.
다행히, 이를 만족하는 해를 찾아내는 방법이 있다. 다들 한 번쯤은 들어봤을 유클리드 호제법을 역이용하면 된다.
유클리드 호제법을 역이용하면, ax + by = d (d는 gcd(a, b))를 만족하는 x, y를 찾아낼 수 있다.
d | c를 만족하므로, 이를 통해 찾아낸 (x, y)에 c / d를 곱하면 최종적으로 우리가 원하는 (x0, y0)를 찾아낼 수 있다.
유클리드 호제법을 통해 알아내는 방법은 다음과 같다.
예시로, 324x + 118y = 8을 만족하는 x, y를 찾아보자.
먼저 gcd(324, 118) = 2 | 8이므로 해가 존재한다.
유클리드 호제법을 통해 gcd를 구하면,
324 = 118 * 2 + 88
118 = 88 * 1 + 30
88 = 30 * 2 + 28
30 = 28 * 1 + 2
28 = 2 * 14 (끝)
로 gcd를 찾아낼 수 있다. 이제 거꾸로 가보자.
2 = 30 - 28
2 = 30 - (88 - 30 * 2) = 30 * 3 - 88
2 = (118 - 88) * 3 - 88 = 118 * 3 - 88 * 4
2 = 118 * 3 - (324 - 118 * 2) * 4 = 118 * 11 - 324 * 4
x = -4, y = 11라는 해를 찾았다.
이제 양변에 4를 곱하면
324 * (-16) + 118 * 44 = 8이 성립하므로, (x0, y0) = (-16, 44)임을 알 수 있다.
이제 한 가지 해를 찾았으니 k의 범위를 확인해주자.
x1 ≤ x0 + b'k ≤ x2라는 등식으로부터 k의 범위를 찾아낼 수 있다. y도 마찬가지로 하면 된다.
x, y로부터 얻은 두 개의 범위에 모두 포함되는 k의 갯수를 세면 답이 나온다.
여기까지가 풀이이다. 이 과정을 오류없이 잘 구현하면 맞았습니다! 메시지를 볼 수 있다..^^
중간에 몇 가지 유의사항을 살펴보면, 음수의 나눗셈에 유의해야 하고(https://jeonggyun.tistory.com/228) 숫자의 범위에 유의해야 한다.
예컨데 유클리드 알고리즘을 통해 구한 x0와 y0가 꼭 정수 범위라는 보장은 없다.
푸는 데 너무 오래 걸려서 억울해서 코드는 안올릴까 하다가 나같은 시행착오를 겪는 사람이 없기를 바라는 마음에서 올린다. 코드가 조금 난잡하다.. ㅎㅎ
'PS > 백준 온라인 저지' 카테고리의 다른 글
조세퍼스 문제 시리즈 (백준 1158, 1168, 11025, 1179) (0) | 2019.08.01 |
---|---|
백준 9009번: 피보나치 (2) | 2019.06.15 |
5월 27일 백준 (1456, 5641, 4134, 9176, 4233) (3) | 2019.05.28 |
제 3회 생각하는 프로그래밍 대회 풀기 (0) | 2019.05.17 |
백준 17115번: Kudeki Chain (0) | 2019.05.17 |