티스토리 뷰

반응형

일반적인 dp에서 진화한 형태이다.

 

import numpy as np
import sys

def multiply_matrix(A, B, mod):
    A = np.array(A)
    B = np.array(B)
    result = np.dot(A, B) % mod
    return result.tolist()

def power_matrix(A, p, mod): #빠른 거듭제곱 알고리즘
    if p == 1: 
        return A
    if p % 2: #n이 홀수라면, 기본 행렬을 n-1번 거듭제곱한 후, 그 결과에 기본 행렬을 한 번 더 곱한다.
        return multiply_matrix(A, power_matrix(A, p-1, mod), mod)
    half = power_matrix(A, p//2, mod)   #n이 짝수라면, 기본 행렬을 n/2번 거듭제곱하고, 자기 자신과 곱한다.
    return multiply_matrix(half, half, mod)

def mushroom(n):
    MOD = 1000000007
    if n == 1:
        return 1
    base_matrix = [[1, 1], [1, 0]]
    result_matrix = power_matrix(base_matrix, n-1, MOD)
    return (result_matrix[0][0] + result_matrix[0][1]) % MOD

a = int(sys.stdin.readline())
print(mushroom(a))  # 예제 입력1

 

피보나치 수열의 dp[i]와 dp[i-1]의 합을 구하는 문제이다.

base matrix는 1,1로 시작한다. 이는 dp[1]과 dp[0]이 각각 1,1이기 때문이다.

 

power_matrix함수에 해당 매트릭스를 넣으면 n이 짝수라고 가정했을 때, n-1이 들어가므로 p%2가 0이 된다.

고로 multiply matrix 함수에 들어간다. A와 그 이전(n-1)의 power matrix가 B로 들어가게 된다.

 

아니라면 p//2번째가 들어가고, 이게 빠른 거듭제곱 알고리즘이 된다.

 

빠른 거듭제곱 알고리즘

 

원래 a^1023을 구하려면 a를 1023번 곱해야 한다.

그러나 빠른 거듭제곱을 사용하면 다르다.

 

“빠른 거듭제곱” 알고리즘은 다음과 같이 작동합니다:

거듭제곱의 지수 n이 짝수인지 홀수인지 확인합니다.
만약 n이 짝수라면, 기본 행렬을 n/2번 거듭제곱한 후, 그 결과를 자기 자신과 곱합니다.
만약 n이 홀수라면, 기본 행렬을 n-1번 거듭제곱한 후, 그 결과에 기본 행렬을 한 번 더 곱합니다.

 

이러면 거듭제곱의 지수를 절반으로 줄여나가면서 거듭제곱을 계산할 수 있게 된다.

 

def multiply_matrix(A, B, mod):
    A = np.array(A)
    B = np.array(B)
    result = np.dot(A, B) % mod
    return result.tolist()

 

 

multiply matrix는 풀어 쓰면 위와 같다.

한마디로 A,B의 dot(행렬곱)을 계산하고, 전체 array에 대해서 mod로 나눠준 값이다.

 

다른 형태로는 순열의 개수가 있다.

import sys

def apply_permutation(permutation, cards):
    # 주어진 순열을 카드 배열에 적용하여 새 배열을 반환
    n = len(permutation)
    new_cards = [0] * n
    for i in range(n):
        new_cards[permutation[i]] = cards[i]
    return new_cards

def multiply_permutations(p1, p2):
    # 두 순열 p1과 p2를 곱하여 결과 순열을 반환
    n = len(p1)
    result = [0] * n
    for i in range(n):
        result[i] = p1[p2[i]]
    return result

def permutation_power(permutation, k, n):
    # 순열을 k번 적용한 결과 순열을 반환
    result = list(range(n))  # 단위 순열 (identity permutation)
    base = permutation[:]
    
    while k > 0:
        if k % 2 == 1:
            result = multiply_permutations(base, result)
        base = multiply_permutations(base, base)
        k //= 2
    
    return result

def main():

    N, K = map(int, input().split())
    A = list(map(int, input().split()))

    # A는 1-based index, 이를 0-based index로 변환
    permutation = [a - 1 for a in A]
    
    # K번 순열을 계산
    final_permutation = permutation_power(permutation, K, N)
    
    # 초기 카드 배열 [1, 2, ..., N]에 최종 순열 적용
    initial_cards = list(range(1, N + 1))
    final_cards = apply_permutation(final_permutation, initial_cards)
    
    # 결과 출력
    print(" ".join(map(str, final_cards)))

# 예제 입력이 주어지는 경우 아래와 같이 테스트 가능
# 예제 실행을 위해 주석 해제하고 필요한 입력을 주어야 합니다.
main()
반응형