11444번 - 피보나치수 6
이번에 기존에 풀던 방식이 메모리 초과가 났다.
그래서 공부를 해보니 피보나치를 행렬로 표현해서 풀 수 있었다..
그리고 이는 O(logN) 의 시간복잡도를 갖게 되므로 어마어마하게 빠른값을 찾을 수 있었다.
(행렬로 계산하게 되면 분할정복의 방식을 사용할 수 있게 되기 때문이다.)
처음에 행렬로 피보나치를 표현해서 뭐하지 했는데, 정말 빨랐다. 그리고 행렬의 곱셈을 미리 풀어봐서 쉽게 풀 수 있었다.
<정답 코드>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | #include<iostream> #include<vector> using namespace std; const long long mod = 1000000007; vector<vector<long long>> multi(vector<vector<long long>> &A, vector<vector<long long>> &B) { vector<vector<long long>> ret(2, vector<long long>(2)); for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { long long sum = 0; for (int m = 0; m < 2; m++) { sum += ((A[i][m]%mod) * (B[m][j]%mod))%mod; } ret[i][j] = sum%mod; } } return ret; } vector<vector<long long>> calc(vector<vector<long long>> &F, long long n) { if (n == 0) { vector<vector<long long>> ret(2, vector<long long>(2)); for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { if (i == j) { ret[i][j] = 1; } else { ret[i][j] = 0; } } } return ret; } else if (n % 2 == 0) { vector<vector<long long>> ret(2, vector<long long>(2)); ret = calc(F, n / 2); return multi(ret, ret); } else { vector<vector<long long>> ret(2, vector<long long>(2)); ret = calc(F, n - 1); return multi(F, ret); } } int main() { long long N; scanf("%lld", &N); vector<vector<long long>> F(2, vector<long long>(2)); for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { if (i == 1 && j == 1) { F[i][j] = 0; } else { F[i][j] = 1; } } } vector<vector<long long>> temp(2, vector<long long>(2)); temp = calc(F, N); printf("%lld\n", temp[0][1]); return 0; } | cs |
반응형