-
백준 6064번 카잉 달력 :: 마이구미알고리즘 풀이/수학 2018. 7. 16. 12:44반응형
이 글은 백준 알고리즘 문제 6064번 "카잉 달력" 을 풀이한다.
일반적으로 시뮬레이션 문제라고 보이지만, 순수하게 접근하면 시간 초과를 초래한다.
별도 알고리즘 지식이 아닌, 시간 초과를 해결하는 다른 접근을 요구한다.
최근에 ICPC 탐사대는 남아메리카의 잉카 제국이 놀라운 문명을 지닌 카잉 제국을 토대로 하여 세워졌다는 사실을 발견했다. 카잉 제국의 백성들은 특이한 달력을 사용한 것으로 알려져 있다. 그들은 M 과 N 보다 작거나 같은 두 개의 자연수 x, y를 가지고 각 년도를 <x:y>와 같은 형식으로 표현하였다. 그들은 이 세상의 시초에 해당하는 첫 번째 해를 <1:1>로 표현하고, 두 번째 해를 <2:2>로 표현하였다. <x:y>의 다음 해를 표현한 것을 <x':y'>이라고 하자. 만일 x < M 이면 x' = x + 1이고, 그렇지 않으면 x' = 1이다. 같은 방식으로 만일 y < N이면 y' = y + 1이고, 그렇지 않으면 y' = 1이다. <M:N>은 그들 달력의 마지막 해로서, 이 해에 세상의 종말이 도래한다는 예언이 전해 온다.
예를 들어, M = 10 이고 N = 12라고 하자. 첫 번째 해는 <1:1>로 표현되고, 11 번째 해는 <1:11>로 표현된다. <3:1>은 13 번째 해를 나타내고, <10:12>는 마지막인 60 번째 해를 나타낸다.
네 개의 정수 M, N, x 와 y가 주어질 때, <M:N>이 카잉 달력의 마지막 해라고 하면 <x:y>는 몇 번째 해를 나타내는 지를 구하는 프로그램을 작성하라.
이 문제의 핵심은 빨간색으로 명시된 문장이 된다.
x < M 이면 x` = x + 1, 그렇지 않으면 x` = 1 이다. y 또한 동일하다.
예를 들면 아래와 같다.
<10, 12>
1번째 해 => <1,1>
2번째 해 => <2,2>
.........
10번째 해 => <10,10>
11번째 해 => <1,11>
12번째 해 => <2,12>
13번째 해 => <3,1>
위처럼 시뮬레이션을 통한 x, y 를 각각 증가시키는 방법을 활용해 구현할 수 있다.
하지만 이 방법은 시간복잡도가 O(M*N) 으로써, 시간제한인 1초를 넘게 되어, 다른 접근이 필요하다.
문제 풀이를 위한 아이디어는 x 를 먼저 맞추고, y 를 따라가게하는 것이다.
x 를 맞추면, y 만을 신경쓰면 된다.
y는 M 만큼 증가하고 N 으로 나머지 연산을 한다면, y 의 값을 알 수 있다는 것은 이해하고 있을 것이다.
이런식으로 y 를 M 만큼 계속 증가시키다보면, y 또한 맞춰질 것이다.
예를 통해 보면 이해하기 쉬울 것이다.
위처럼 x는 5로 처음부터 끝까지 고정시킨다.
그러면서 M 만큼 계속해서 y 를 증가시킬때마다, N 으로 나머지 연산을 해주면 현재의 y 를 알 수 있다.
이미 x 는 5 로 맞춰져있기 때문에, y 가 6이 되는 순간에 우리가 원하는 <5:6> 를 구해졌다.
예외인 경우를 위해서 최소공배수를 활용한다.
문제에서도 마지막 해의 번째를 알려주었다. 이건 힌트일 수도 있었다.
10, 12 의 최소공배수는 60이다.
주어지는 M,N 의 최소공배수를 넘는다면 예외라고 볼 수 있다.
알고 나면 정말 허무한 문제가 된다.
쉬운 문제이면서, 다른 접근을 요구하는 문제로써, 좋은 문제라고 생각한다.
Github - https://github.com/hotehrud/acmicpc/blob/master/algorithm/math/6064.java
12345678910111213141516171819202122232425262728293031323334353637383940private void solve() {int t = sc.nextInt();StringBuilder sb = new StringBuilder();while (t-- > 0) {int m = sc.nextInt();int n = sc.nextInt();int x = sc.nextInt();int y = sc.nextInt();int cnt = x % (m + 1);int tempY = x;for (int i = 0; i < n; i++) {int ty = tempY % n == 0 ? n : tempY % n;if (ty == y) {break;}tempY = ty + m;cnt += m;}sb.append(cnt > lcm(m, n) ? "-1" : cnt);sb.append("\n");}System.out.println(sb.toString());}public static int gcd(int a, int b) {while (b != 0) {int r = a % b;a = b;b = r;}return a;}public static int lcm(int a, int b) {return a * b / gcd(a, b);}cs 반응형'알고리즘 풀이 > 수학' 카테고리의 다른 글
백준 15685번 드래곤 커브 :: 마이구미 (4) 2018.11.17 백준 1652번 누울 자리를 찾아라 :: 마이구미 (0) 2018.08.14 백준 14890번 경사로 :: 마이구미 (0) 2018.04.06 백준 10837번 동전 게임 :: 마이구미 (0) 2018.04.01 백준 1244번 스위치 켜고 끄기 :: 마이구미 (0) 2018.03.06