본문 바로가기

카테고리 없음

피보나치 수열과 행렬 거듭제곱

반응형

백준 블로그 글을 보며 공부한 내용입니다. 

원래 코드 및 글 : https://www.acmicpc.net/blog/view/28


#include <iostream>
#include <vector>
using namespace std;
typedef vector<vector<long long>> matrix;
const long long mod = 1000000007LL;

//연산자 재 정의.
// 정사각행렬의 곱셈
//c++는 객체에 따라서 연산자를 알아서 바꿔서 해석해주므로 그냥 * 로 이용할 수 있음
matrix operator * (const matrix &a, const matrix &b){
int n = a.size();
//vector <long long> v(n,0) means you're creating a vector of size n and initializing its elements to 0
//행렬 c은 vector<long long>(n) 를 원소로 갖는 벡터 n개
matrix c(n, vector<long long>(n));
for(int i = 0 ; i < n ; i ++){
for(int j = 0 ; j < n ; j++){
for(int k = 0 ; k < n ; k ++){
c[i][j] += a[i][k]*b[k][j];
}
// 이 부분은 그냥 피보나치 문제에서 주어진것 1000000007LL 로 모듈로 한 값을 반환하라 했음
c[i][j] %= mod;

}
}
return c;
}

int main() {
long long n;

cin >> n;
if (n <= 1) {
cout << n << '\n';
return 0;
}

matrix ans = {{1, 0}, {0, 1}};
matrix a = {{1, 1}, {1, 0}};

/*
* n==11일 때
* 11%2 = 1 -> ans = ans*a 하면 그냥 a;
* 11/2 = 5 하고 a = {{1, 1}, {1, 0}}^2;
*
* 5%2 = 1 -> ans = a*a^2 = {{1, 1}, {1, 0}}^3
* 5/2 = 2 하고 a 값은 {{1, 1}, {1, 0}}^4
*
* 2%2 = 0
* 2/2 = 1 하고 a값은 {{1, 1}, {1, 0}}^8
*
* 1%2 = 1 -> ans = {{1, 1}, {1, 0}}^3 * {{1, 1}, {1, 0}}^8 = {{1, 1}, {1, 0}}^11;
* -끝
*
* 이걸 어떻게 알았담..
* */
while (n > 0) {
if (n % 2 == 1) {
ans = ans * a;
}
a = a * a;
n /= 2;
}

cout << ans[0][1] << '\n';

return 0;

} 


[새로 알게된 내용]


typedef vector<vector<long long>> matrix;

간단하게 한줄짜리 typedef


* matrix c(n, vector<long long>(n));

c라는 메트릭스를 새로 선언하고, 안에 길이 n짜리 벡터를 넣는데 이 각각 벡터들은 또 길이 n짜리 long long 벡터 초기화 되어있음

다른예시  

vector <long long> v(n,0)

벡터 v는 길이 n짜리 long long 벡터이며 각각 원소들은 0으로 초기화 되어있음.


*const long long mod = 1000000007LL;

long long int 선언


*matrix operator * (const matrix &a, const matrix &b){

연산자 재정의....! *연산자를 객체에 따라 다르게 작동하도록 오버로딩 할 수 있음

(갑자기 헷깔려서 찾아봄 : 오버로딩은 같은 함수 이름을 피연산자에 따라 다르게 사용하는것, 오버라이딩은 부모 클라스의 메서드에 덮어쓰는것)


*행렬연산 알고리즘

for(int i = 0 ; i < n ; i ++){
for(int j = 0 ; j < n ; j++){
for(int k = 0 ; k < n ; k ++){
c[i][j] += a[i][k]*b[k][j];
}
}

}

혼자 짤려고 했으면 어떻게 접근할지 고민 했을듯...


*행렬 거듭제곱 빠르게 알고리즘

  

matrix ans = {{1, 0}, {0, 1}};

while (n > 0) {
if (n % 2 == 1) {
ans = ans * a;
}
a = a * a;
n /= 2;
}


반응형