✅문제 - 피보나치 수 6 (11444번)
✅필요 알고리즘 개념 - 분할 합
🔵 자연수 a의 1024제곱을 구하는 상황
◼ Dynamic Programming이나 재귀를 이용하면 최소 1024번의 연산을 진행해야 한다.
◼ (a^2)^2 = a^4 인 성질을 이용하면 a^1024 를 10번의 계산으로 구할 수 있다.
이는 제곱 연산의 분할 합 개념을 이용한 것이다.
🔵 피보나치 수열의 분할 합 개념
피보나치 수열을 행렬을 통하여 구할 수 있다.
이 개념을 적용하면 피보나치 수열을 다음과 같이 표현할 수 있다.
이 때 행렬의 n제곱을 하는 과정에서 위에 말한 분할 합의 개념을 적용하면 행렬의 n제곱을 쉽게 구할 수있다.
이를 통해 피보나치 수열의 n항을 쉽게 구할 수 있다.
✅코드
import sys
input = sys.stdin.readline
prime_num = 1000000007
mat = [[1,1],[1,0]]
# 2*2 행렬의 곱을 구하는 함수
def mul_matrix(a:list,b:list):
changed = list(zip(*b))
result = [[0,0],[0,0]]
for i in range(2):
for j in range(2):
tmp = 0
for k in range(2):
tmp += a[i][k]*changed[j][k]
result[i][j] = tmp%prime_num
return result
# 2*2 행렬의 제곱을 구하는 함수
def suquare_matrix(a:list):
changed = list(zip(*a))
result = [[0,0],[0,0]]
for i in range(2):
for j in range(2):
tmp = 0
for k in range(2):
tmp += a[i][k]*changed[j][k]
result[i][j] = tmp%prime_num
return result
# 행렬의 n제곱을 구하는 함수 / 분할합 개념과 재귀를 이용해 구성
def involution_matrix(n:int):
if n == 1:
return mat
else:
if n % 2:
return mul_matrix(suquare_matrix(involution_matrix((n-1)//2)),mat)
else:
return suquare_matrix(involution_matrix(n//2))
n = int(input().rstrip())
if n <= 2:
print("1")
else:
# 피보나치의 1항과 2항이 1인 것을 이용해 합을 구한다.
print(sum(involution_matrix(n-2)[0])%prime_num)
'Algorithm & Data Structure' 카테고리의 다른 글
[백준] 공유기 설치 (2110번) - Python (0) | 2023.01.25 |
---|---|
[백준] 히스토그램에서 가장 큰 직사각형 (6549번) - Python (0) | 2023.01.24 |
[백준] AC (5430번) - Python (0) | 2023.01.19 |
[백준] 나머지 합 (10986번) - Python (0) | 2023.01.17 |
[백준] 평범한 배낭(12865번) - Python (0) | 2023.01.17 |