일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 마진 상쇄
- 이분탐색
- react
- 분할정복
- 수학
- 렌더링 최적화
- next14
- 슬라이딩 윈도우
- webpack5
- 값복사
- 레이아웃 스래싱
- 공백찾기
- 구현
- react18
- 브루트포스
- 컴포넌트 생명주기
- 누적합
- 리액트
- 정적타입언어
- 재귀
- 백준
- 레퍼런스복사
- 즉시실행함수
- 두 포인터
- SW EA
- BFS
- 이벤트 생명주기
- 동적타입언어
- webpack
- vscode
- Today
- Total
D.JOUNG
백준 문제풀이 : (6064) 카잉 달력 - Python 본문
문제 : https://www.acmicpc.net/problem/6064
6064번: 카잉 달력
입력 데이터는 표준 입력을 사용한다. 입력은 T개의 테스트 데이터로 구성된다. 입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 각 테스트 데이터는 한 줄로 구성된다.
www.acmicpc.net
시간 제한 | 메모리 제한 | 난이도 | 알고리즘 분류 |
2초 | 64 MB | Silver 1 | 수학 / 정수론 |
문제
풀이
c++로 풀이했을 때는 조금 복잡한 규칙을 만들어서 풀이했었는데, 정답이 잘 나와 다시 고민하지 않고 넘어갔었다. 하지만 파이썬으로 같은 풀이법을 옮겼더니 곧장 시간 초과를 뿜어내더라...
그래서 풀이 과정을 다시한번 되짚어보며, 계산이나 반복을 줄일 수 있는 방법을 찾아봤다.
문제의 정답을 변수 day라고 정의한다. M과 N, 그리고 x와 y의 관계에 대해 조금만 고민해보면 다음과 같은 규칙을 찾아낼 수 있다.
- day%M = x 이고, day%N = y 이다.
그리고 이 규칙은 바로 다음과 같이 바꿔 쓸 수 있다.
- (day-x)%M = 0 이고, (day-y)%N = 0 이다.
위 규칙이 성립할 수 있는 이유는 간단하다.
날짜가 하루 씩 지나갈 때 마다 x와 y의 값은 함께 1씩 증가하고, 각가 M과 N 숫자를 마주쳤을 때 다시 1로 돌아가기 때문이다.
즉, 예를 들어 M, N의 값이 1=5, 4 라면, x와 y 값은 날짜의 흐름에 따라 아래와 같이 변한다는 뜻이다.
(day ) x : y
(day1) 1 : 1
(day2) 2 : 2
(day3) 3 : 3
(day4) 4 : 4
(day5) 5 : 1
(day6) 1 : 2
(day7) 2 : 3
(day8) 3 : 4
(day9) 4 : 1
x와 y는 M과 N 단위로 초기화 된다. 그러니 day를 M으로 나눴을 때의 나머지는 항상 x일 수 밖에 없다. (y의 공식도 마찬가지다.)
여기까지 알아냈다면 일단 풀이법을 떠올리는 것은 어렵지 않다.
day를 1씩 증가시키는 for문을 만들어 규칙에 맞는 day값을 찾아내기만 하면 되기 때문이다.
하지만 그렇게 전수조사를 하면 Python은 물론이고 c++에서도 시간초과가 발생한다.
탐색 시간을 줄일 수 있는 방법을 고민해봐야 한다는 뜻이다.
일반적으로 가장 단순하게 탐색 시간을 줄일 수 있는 방법은, day의 증가값을 더 큰 수로 늘리는 것이다. 이 방법으로 조금 더 고민해보면, day에 대한 규칙을 한 가지 더 발견할 수 있다.
- day 는 x+M*i 이거나, y+N*j 이다. (i와 j는 각각 x와 y가 초기화 된 횟수다.)
예를 들어 M과 x를 기준으로 생각해 볼 경우, day%M은 무조건 x이기에 day는 x에 M을 더해나가는 수열의 수 중 하나일 수 밖에 없다.
이 방법을 통해 day의 초기값을 x와 y 중 하나로 정하고 반복 시의 증가값을 M또는 N으로 늘려보았다. 그랬더니 Python에서도 무사히 성공 판정을 받았다.
M,x와 N,y 중 어떤 규칙을 증가값으로 삼을 지는 M과 N 중 어떤 수가 더 큰 지로 정했다. (조금이라도 증가값을 늘려, 반복을 줄이기 위해...)
코드 작성
import sys;
input = sys.stdin.readline;
printt = sys.stdout.write;
T = int(input());
resultF = "";
for t in range(0, T) :
M, N, x, y = map(int, input().split(' '));
result = -1;
mORn = M if M>N else N; //M과 N중 더 큰 값을 저장
xORy = x if mORn==M else y; //위에서 M이 선택됐다면 x를, N이 선택됐다면 y를.
if x==y : result=x; //x와 y 값이 같다면 day=x=y 이다. (x와 y는 항상 함께 1씩 증가하고, 두 수가 다시 같아지는 시점은 <M, N>에 도달한 다음 날이기 때문.
else :
day=xORy; //day의 초기값 지정
while day<=M*N :
if ((day-x)%M==0) and ((day-y)%N==0) :
result=day;
break;
day+=mORn;
resultF+=(f'{result}\n');
printt(resultF);
END.
'알고리즘 > 백준' 카테고리의 다른 글
백준 문제풀이 : (2018) 수들의 합 5 - c/c++ (1) | 2023.11.30 |
---|---|
백준 문제풀이 : (10986) 나머지 합 - c/c++ (0) | 2023.11.28 |
백준 문제풀이 : (1790) 수 이어 쓰기 2 - c/c++ (1) | 2023.11.21 |
백준 문제풀이 : (2022) 사다리 - c/c++ (0) | 2023.11.21 |
백준 문제풀이 : (1105) 팔 - c/c++ (0) | 2023.11.18 |