https://www.acmicpc.net/problem/11444
문제
피보나치 수는 0과 1로 시작한다. 0번째 피보나치 수는 0이고, 1번째 피보나치 수는 1이다. 그 다음 2번째 부터는 바로 앞 두 피보나치 수의 합이 된다.
이를 식으로 써보면 Fn = Fn-1 + Fn-2 (n ≥ 2)가 된다.
n=17일때 까지 피보나치 수를 써보면 다음과 같다.
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597
n이 주어졌을 때, n번째 피보나치 수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 n이 주어진다. n은 1,000,000,000,000,000,000보다 작거나 같은 자연수이다.
출력
첫째 줄에 n번째 피보나치 수를 1,000,000,007으로 나눈 나머지를 출력한다.
DP를 사용해서 풀이를 해보려고 했지만 당연하게도 최대 n이 1,000,000,000,000,000,000 라서 시간초과가 출력됩니다.
분할 정복을 사용해서 풀어보려 고민하였지만 아이디어가 떠오르지 않아 다른 사람 풀이를 참고하였습니다.
해결 방법으로는 앞서 풀었는 행렬의 거듭제곱을 사용하는 것입니다.
피보나치 수열의 점화식을 행렬의 곱셈으로 표현하면 다음과 같습니다.
\(\rightarrow\) \(F_{n+2} = 1 \times F_{n+1} + 1 \times F_{n}\), \(F_{n+1} =1 \times F_{n+1} + 0 \times F_{n}\)
이름 다음과 같이 확장이 가능합니다.
이를 계속해서 확장한다면 다음과 같이 행렬의 거듭 제곱 형태로 표현이 가능합니다.
import sys
input = sys.stdin.readline
N = int(input())
A = [[1, 1], [1, 0]]
def power(A, B):
n = len(A)
answer = [[0] * n for _ in range(n)]
for r in range(n):
for c in range(n):
s = 0
for a, b in zip(A[r], B[:]):
s += a * b[c]
answer[r][c] = s % 1000000007
return answer
def div_power(A, B):
if B == 1:
return A
T = div_power(A, B//2)
if B % 2:
return power(power(T, T), A)
else:
return power(T, T)
answer = div_power(A, N)
print(answer[0][1] % 1000000007)
'Coding Test > 백준' 카테고리의 다른 글
[백준] / [Python] / [10816] 숫자 카드 2 (0) | 2023.01.09 |
---|---|
[백준] / [Python] / [1920] 수 찾기 (0) | 2023.01.09 |
[백준] / [Python] / [10830] 행렬 제곱 (0) | 2023.01.04 |
[백준] / [Python] / [1629] 곱셈 (0) | 2023.01.03 |
[백준] / [Python] / [2740] 행렬 곱셈 (0) | 2022.12.30 |