Coding Problem/백준

[백준] 11444 - 피보나치 수 6

마탁이 2021. 6. 23. 11:20

https://www.acmicpc.net/problem/11444

 

11444번: 피보나치 수 6

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

www.acmicpc.net

  • 피보나치를 활용한 문제지만 입력과 모듈러 연산이 추가되었다는 점을 주의해야한다.
  • 기존의 피보나치 수 계산 Fn+2 = Fn+1 + Fn (n >= 2)를 그대로 사용하면 시간초과가 발생한다.
  • 찾아보니 행렬연산으로 대체할 수 있었다.

더보기
#include <iostream>
#include <vector>

using namespace std;

// global
typedef long long VERYLONG;
typedef vector<vector<VERYLONG>> MATRIX;

const VERYLONG N_MAX = 1000000000000000000;
const VERYLONG MODULER = 1000000007;

MATRIX A_Matrix;

// method
MATRIX CalcPibo(MATRIX& src, VERYLONG exp);
MATRIX MultiMatrix(MATRIX& lhs, MATRIX& rhs);

int main()
{
	/*
	* ref : https://st-lab.tistory.com/252
	* [ F_n+2 ] = [ 1  1 ] [ F_n+1 ]
	* [ F_n+1 ] = [ 1  0 ] [ F_n   ]
	*/

	// init
	std::ios::sync_with_stdio(false);

	vector<VERYLONG> aRow = { 1, 1 };
	A_Matrix.push_back(aRow);
	aRow = { 1, 0 };
	A_Matrix.push_back(aRow);

	// input
	VERYLONG n = 0;
	(void)scanf("%lld", &n);

	if (0 == n)
	{
		printf("0\n");
		return 0;
	}
	else if (1 == n)
	{
		printf("1\n");
		return 0;
	}

	// calc
	MATRIX answer = CalcPibo(A_Matrix, n-1);

	// print
	printf("%lld\n", answer[0][0]);

	return 0;
}

MATRIX CalcPibo(MATRIX& src, VERYLONG exp)
{
	if (1 == exp)
		return src;

	MATRIX calcResult = CalcPibo(src, exp / 2);
	if (0 != exp % 2)
	{
		calcResult = MultiMatrix(calcResult, calcResult);
		calcResult = MultiMatrix(calcResult, A_Matrix);

		return calcResult;
	}

	calcResult = MultiMatrix(calcResult, calcResult);

	return calcResult;
}

MATRIX MultiMatrix(MATRIX& lhs, MATRIX& rhs)
{
	MATRIX retValue;

	const int matrixSize = lhs.size();
	for (int row = 0; row < matrixSize; row++)
	{
		vector<VERYLONG> rowList;
		
		for (int col = 0; col < matrixSize; col++)
		{
			VERYLONG data = 0;

			auto& lhsRow = lhs[row];
			int rhsRow = 0;
			
			for (auto& lhsVal : lhsRow)
			{
				data += (lhsVal * rhs[rhsRow][col]);
				rhsRow++;
				if (matrixSize <= rhsRow)
					rhsRow = 0;
			}
			data %= MODULER;
			rowList.push_back(data);
		}

		retValue.push_back(rowList);
	}

	return retValue;
}

'Coding Problem > 백준' 카테고리의 다른 글

[백준] 10830 - 행렬 제곱  (0) 2021.06.22
[백준] 2740 - 행렬 곱셈  (0) 2021.06.22
[백준] 1780 - 종이의 개수  (0) 2021.06.21
[백준] 1992 - 쿼드트리  (0) 2021.06.21
[백준] 2630 - 색종이 만들기  (0) 2021.06.21