백준 / 실버 1 / 1074 Z / Python [재귀, 분할정복, 수열]

jjin·2023년 10월 21일
0

수열의 일반항 발견해서 대입하면 되는 문제였다.

1. N <= 15, 2^15 = 1024 * 32 = 32000 * 32000
다 구할 순 없어 그냥 연산 방법을 구해야해

2. order[r][c] = i
N = 2였을 때, r = 3, c = 3이면 15인데
r == 0, 1 이면 상단. 즉 r < 2^(N-1)
r == 2, 3 이면 하단 r >= 
c == 0, 1 이면 좌단 c <
c == 2, 3 이면 우단 c >=

다음 걸 보기 위해 15 // 4를 했는데 4는 2^2(N-1)

좌상단: i = 0 * 2^2(N-1)
    의 좌상단: + 0 * 2^2(N-2)
        ...        + 0 * 2^2(0)
우상단: 1 * 2^N
좌하단: 2 * 2^N
우하단: 3 * 2^N

3. 반복 또는 재귀

4. 엣지 케이스
경계값 주의

느낀 점: 재귀 머리아프니 최대한 반복으로

재귀

탑다운, 첫 풀이

import sys
input = sys.stdin.readline
N, r, c = map(int, input().split())

def order(n, r, c):
    if (n == 0):
        return 0
    div = 0
    if r // 2 ** (n-1) > 0:
        div += 2
    if c // 2 ** (n-1) > 0:
        div += 1
        
    return order(n - 1, r % 2**(n - 1), c % 2**(n - 1)) + div * 2**(n - 1) * 2**(n - 1)

print(order(N, r, c))

탑다운, 일반항 slided

def order(N, r, c):
    N -= 1
    if N == 0: 
    	return 0
    div = 2 * (r // 2**N) + c // 2**N
    return order(N, r % 2**N, c % 2**N) + div * 2**N * 2**N
    
print(order(N, r, c))

바텀업

def order(n, r, c):
    if (n == 0):
        return 0
    return order(n - 1, r // 2, c // 2) * 2 * 2 + (r % 2) * 2 + (c % 2)

print(order(N, r, c))

반복

탑다운

ans = 0

while(N--):
    div = 2 * (r // 2**N) + c // 2**N
    ans += div * 2**N * 2**N
    r %= 2 ** N
    c %= 2 ** N

print(ans)

바텀업


ans = 0

for i in range(N):
    div = 2 * (r % 2) + c % 2
    ans += div * 2**i * 2**i
    r //= 2
    c //= 2
    
print(ans)
profile
진짜

0개의 댓글