제목 : 분수찾기
1/1 | 1/2 | 1/3 | 1/4 | 1/5 | … |
2/1 | 2/2 | 2/3 | 2/4 | … | … |
3/1 | 3/2 | 3/3 | … | … | … |
4/1 | 4/2 | … | … | … | … |
5/1 | … | … | … | … | … |
… | … | … | … | … | … |
-
문제 : 이와 같이 나열된 분수들을 1/1 → 1/2 → 2/1 → 3/1 → 2/2 → … 과 같은 지그재그 순서로 차례대로 1번, 2번, 3번, 4번, 5번, … 분수라고 하자. X가 주어졌을 때, X번째 분수를 구하는 프로그램을 작성하시오.
- 입력 : 첫째 줄에 X(1 ≤ X ≤ 10,000,000)가 주어진다.
- 출력 : 첫째 줄에 분수를 출력한다.
주어진 분수들을 지그재그로 순열을 만들었을 때 X번 째 분수를 찾아야 하는 문제이다. 사선으로, 방향을 바꿔가며 순열이 주어지는 상황인데 이게 말로하면 와닿지 않을 수 있다. 하지만 이걸 다음과 같이 묶어서 표현하면 이해가 쉽게 갈 것이다. (1/1) → (1/2 → 2/1) → (3/1 → 2/2 → 1/3) → (1/4 → 2/3 → 3/2 → 4/1) → …
라떼는 이걸 군수열(group sequence)라고 고등학교 수학 때 배웠었는데 요즘도 배우는지 모르겠다. 요 근래 고교수학 과정이 가벼워 지고 있다는 얘길 들어서 …
하여간 군수열로 접근하면 문제는 간단해진다. X를 받았을 때 알아야할 것은
- 몇 번째 군(group)에 속하는가?
- 해당 군 내에서 몇 번째 수열인가?
이다.
각 군은 공차 1의 등차수열로 이루어진 원소 갯수를 포함한다. 즉 {a_n}에 속한 원소의 갯수는 sum(n)이다. 만약 X=7이라면, (1+2+3) < 7 ≤ (1+2+3+4) 이기 때문에 {a_4}에 속한다는 걸 알 수 있다. 이런식으로 1번은 해결할 수 있다. 두 번째 요소인 “해당 군 내에서 몇 번째 수열인가?” 또한 이런식으로 해결 할 수 있다.
X=7일 때, X가 4번 군에 속한다는 사실을 앞서 말한 방식으로 알아내었다. 그렇다면 그 이전 군인 3번군까지 속한 원소의 갯수를 X에서 빼주면 간단하게 몇 번째 원소인지도 알 수 있다. 3번 군까지 속한 원소의 갯수는 1+2+3=6이므로 7-6 = 1, 즉 첫 번째 원소라는걸 쉽게 알 수 있다.
그렇다면 X=7일 때 정답은 어떻게 구할까? 첫 번째 군은 (1/1), 두 번째 군은 (1/2, 2/1), 세 번째 군은 (3/1, 2/2, 1/3) … 규칙이 보이는가?
맞다. 각 군의 분자와 분모의 합은 동일하며, 그 합은 공차가 1인 등차수열을 이룬다. 또한 짝수번 째 군은 분자가 1로 시작하며 홀수번 째 군은 분모가 1로 시작한. 우리는 이미 주어진 X=7가 4번 째 군의 첫 번째 원소라는 사실을 알고 있다. 이를 통해 4번 군은 분자+분모 = 5라는 사실과 분자가 1로 시작하는 걸 알고 있으므로 답은 1/4라는걸 유추할 수 있다!
코드는 다음과 같다.
import sys
n = int(sys.stdin.readline())
if n==1:
group = 1
nth=0
else:
i=1
j=1
while n>j:
i+=1
j+=i
group = i
nth = n-j+i-1
if(turn%2==1):#홀수
a = group - nth
b = nth + 1
else:
a = 1 + nth
b = group+1 -a
print('%d/%d'%(a, b))
코드 자체는 훨씬 효율적으로 짤 방법이 있겠지만, 솔직히 말해서 이게 직관적으로 이해도 쉽고… 무엇보다 문제에서 그런걸 요구하지 않는다. 라는 변명을 덧붙인다.