본문 바로가기

분할 정복을 이용한 거듭제곱/행렬 거듭제곱

백준 11443번: 짝수번째 피보나치 수의 합

 

www.acmicpc.net/problem/11443

 

11443번: 짝수번째 피보나치 수의 합

첫째 줄에 n이 주어진다. n은 1,000,000,000,000,000,000보다 작거나 같은 자연수이다.

www.acmicpc.net


이 문제는 이전글과 거의 비슷한 성질을 활용합니다. (백준 11442번: 홀수번째 피보나치 수의 합)

 

바로 $ \sum_{i=1}^{n}F_{2i}=F_{2n+1}-1 $ 입니다.

 

이를 이용하여 구현하면 됩니다.

 

0번째 피보나치 수에 관한 언급이 있지만 어차피 0이므로 고려하지 않아도 충분합니다.

 

#include <stdio.h>

typedef struct {
	long long array[2][2];
} Matrix;

Matrix matrix_multiply_modular (Matrix A, Matrix B, long long M);
Matrix matrix_power_modular (Matrix A, long long K, long long M);

long long Get_Fibonacci (long long N);

int main() {
	long long n;
	scanf("%lld", &n);
	n /= 2;
	printf("%lld", Get_Fibonacci(2*n + 1) - 1); // F(2) + F(4) + ... + F(2n) = F(2n+1) - 1
	return 0;
}

Matrix matrix_multiply_modular (Matrix A, Matrix B, long long M) {
	Matrix result;
	int i, j, k;
	for (i = 0; i < 2; i++) {
		for (j = 0; j < 2; j++) {
			result.array[i][j] = 0;
			for (k = 0; k < 2; k++) {
				long long temp = (A.array[i][k] * B.array[k][j]) % M;
				result.array[i][j] = (result.array[i][j] + temp) % M;
			}
		}
	}
	return result;
}

Matrix matrix_power_modular (Matrix A, long long K, long long M) {
	Matrix result;
	result.array[0][0] = result.array[1][1] = 1;
	result.array[0][1] = result.array[1][0] = 0;
	while (K > 0) {
		if (K & 1) {
			result = matrix_multiply_modular (result, A, M);
		}
		A = matrix_multiply_modular (A, A, M);
		K >>= 1;
	}
	return result;
}

long long Get_Fibonacci (long long N) {
	Matrix Base;
	Base.array[0][0] = Base.array[0][1] = Base.array[1][0] = 1;
	Base.array[1][1] = 0;
	Base = matrix_power_modular (Base, N, 1000000007);
	return Base.array[0][1];
}

 

(C11, 1116KB, 0ms, 제출번호 25615614)