https://www.acmicpc.net/problem/11444
MOD가 10의 거듭제곱꼴이 아니므로 피사노 주기를 사용할수 없다. 따라서 행렬곱을 이용해야 한다.
https://www.acmicpc.net/blog/view/28
설명은 이곳 참고
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
typedef vector<vector<ll>> matrix;
const ll MOD = 1000000007LL;
matrix operator * (const matrix& a, const matrix& b) {
int n = a.size();
matrix c(n, vector<ll>(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];
}
c[i][j] %= MOD;
}
}
return c;
}
int main() {
ll n; cin >> n;
if (n <= 1) {
cout << n << '\n';
return 0;
}
matrix ans = { {1,0}, {0,1} };
matrix a = { {1,1}, {1,0} };
while (n > 0) {
if (n % 2 == 1) ans = ans * a;
a = a * a;
n /= 2;
}
cout << ans[0][1] << '\n';
}
코드 복붙. main 안쪽은 재귀를 이용한 분할정복을 간략화 한 것.
#include <iostream>
#include <map>
using namespace std;
typedef long long ll;
map<ll, ll> dp;
const ll MOD = 1000000007LL;
ll fibo(ll k) {
if (k <= 1) return k;
if (k == 2) return 1;
if (dp.count(k) > 0) return dp[k];
ll& ret = dp[k];
if (k % 2 == 1) {
ll m = (k + 1) / 2;
ll t1 = fibo(m);
ll t2 = fibo(m - 1);
ret = t1 * t1 + t2 * t2;
ret %= MOD;
}
else {
ll m = k / 2;
ll t1 = fibo(m - 1);
ll t2 = fibo(m);
ret = (2LL * t1 + t2) * t2;
ret %= MOD;
}
return ret;
}
int main() {
ll n; cin >> n;
cout << fibo(n) << '\n';
}
피보나치 홀수일때, 짝수일때를 나눠서 푼 코드. O(logn)에 수행됨.
map을 이용해서 dp를 짤 수 있다. (count로 메모가 됐는지 확인, 인덱스로 접근 가능)
'알고리즘 > 백준 & swacademy' 카테고리의 다른 글
BOJ 11973 - Angry Cows (usaco silver, 이분탐색) (0) | 2019.10.01 |
---|---|
BOJ 11997 - Load Balancing (usaco silver, 차원압축) (0) | 2019.09.29 |
BOJ 2749 - 피보나치 3 (MOD=10^k꼴일 때 주기 이용) (0) | 2019.09.27 |
BOJ 7535 - A Bug's Life (0) | 2019.08.19 |
BOJ 4013 - ATM (0) | 2019.08.19 |