Notice
Recent Posts
Recent Comments
«   2025/02   »
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
Tags
more
Archives
Today
Total
관리 메뉴

seven05

[SW사관학교 정글] Week01 알고리즘 시험 - BOJ 5904번 moo 게임 본문

SW JUNGLE 9기/알고리즘

[SW사관학교 정글] Week01 알고리즘 시험 - BOJ 5904번 moo 게임

박상비누 2024. 9. 3. 21:05

 

https://www.acmicpc.net/problem/5904

시행착오: 단순 재귀함수로 생각하고 접근했었음

def moo(k):
    if k==0:
        return "moo"
    return moo(k-1) + "m" + "o"*(k+2) + moo(k-1)
for i in range(int(N ** (1/2))):
    if len(moo(i)) > N:
        K = i
        break
# print(len(moo(N)))
# print(K)
# print(moo(K))
print(moo(K)[N-1])

 

문제 핵심:

S(k) = S(k-1) + "m" + "o" * (k+2) + S(k-1)

얼핏보면 재귀함수로 문자열을 저장하면될것처럼 보이는 단순한 문제이지만 입력값 N의 범위가 10^9 이기때문에 문자열을 저장해서 인덱스를 찾으려고하면 메모리 초과가 날수밖에없다.

핵심은 문자열의 길이는 규칙적으로 증가하므로 (현재길이) = (이전길이) *2 + K+3

앞부분 S(k-1) 인지  moo... 부분인지 뒷부분 S(k-1) 부분인지 구별하고 moo... 부분에 있는것으로 판단되면 첫번째 인덱스면 m 나머지 부분이면 o를 리턴하면 된다.

 

풀이 코드

import sys
sys.setrecursionlimit(1000000)		# 파이썬 재귀 제한 해제		
N = int(sys.stdin.readline().strip())
K = 0
Length = 3				# 기본 moo 길이
while Length < N:			# 주어진 N을 만족하는 k값찾기
    K += 1
    Length = 2 * Length + (K + 3)	# 현재길이 = 이전길이*2 + k + 3
# print(K)
def find_n(k,n,length):
    global prev_len
    if k == 0:				# 종료조건
        return "moo"[n-1]   
    prev_len = (length-(k+3)) // 2
    mid_len = k + 3						
    if n < prev_len:			# 앞부분
        return find_n(k - 1, n,prev_len)
    elif n < prev_len + mid_len:	# moo... 부분
        if n == prev_len+1:
            return "m"
        else:
            return "o"
    else:				# 뒷부분
        return find_n(k - 1, n - prev_len - mid_len,prev_len)

print(find_n(K,N,Length))