https://www.acmicpc.net/problem/1788
코드설명
동적프로그래밍(DP, Dynamic Programming) + 수학(Math) 을 활용합니다.
처음에 문제에서 개선시켰던 점은,
1. % MOD를 어느부분에 정확히 해야하나?
아래와 같이 하나의 MOD로 분배 법칙에 의해 자동으로 나눠집니다.
return cache[n] = (plusFibo(n - 1) + plusFibo(n - 2) ) %MOD ;
2. minusFibo, plusfibo로 두개의 함수로 나누어서 처리했는데, 한개의 함수로 바꿔서 깔끔하게 구현도 가능할 것 같지만, 원활하게 2개루 구현했습니다. (무엇이 더 나은지는 모르겠습니다.) 단순히 if(n > 0) 혹은 (n < 0) 이렇게 처리하고 하면 되겠지요. 또, F[-1) == 1, 반드시 1이라는 것은 알 수 있으니 이를 기저조건으로 두면 되겠지요.
3. 저는 아래와 같이 직접 식을 F(n) = F(N+2) - F(N+1) 이라는 식을 세워서 구현했는데,
다른 분들이 본 코드를 보니, F(-1) 과 F(1), F(-2)와 F(2), ... 결국 피보나치 수가 같았습니다. 음수일때 짝수인경우(-2, -4, -6, ... 일때만 음수로 바꿔서 처리)만 부호가 다르므로 부호만 바꾸어서 반환하면 됩니다. 이렇게 규칙을 찾을경우 훨씬 빠르게 계산해낼 수 있습니다.
코드
처음에 푼 코드입니다.
package Main;
import java.util.*;
import java.io.*;
public class Main {
public static int N, M;
public static int[] cache;
public static int answer = 0;
public static int MAX = (int) Math.pow(10, 6);
public static int MOD = (int) Math.pow(10, 9);
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
cache = new int[MAX + 1];
Arrays.fill(cache, Integer.MIN_VALUE);
if(N >= 0) {
answer = plusFibo(N);
if(answer > 0) System.out.println(1);
else if(answer == 0) System.out.println(0);
else System.out.println(-1);
System.out.println(answer);
}
else if(N < 0) {
answer = minusFibo(N);
if(answer > 0) System.out.println(1);
else if(answer == 0) System.out.println(0);
else System.out.println(-1);
System.out.println(Math.abs(minusFibo(N)));
}
}
public static int plusFibo(int n) {
if(n == 0) return 0;
if(n == 1) return 1;
if(cache[n] != Integer.MIN_VALUE) return cache[n];
return cache[n] = (plusFibo(n - 1) + plusFibo(n - 2) ) %MOD ;
}
public static int minusFibo(int n) {
if(n == 0) {
return 0;
}
if(n == 1) {
return 1;
}
if(cache[n + MAX] != Integer.MIN_VALUE) return cache[n + MAX];
return cache[n + MAX] = (minusFibo(n + 2) - minusFibo(n + 1) ) % MOD;
}
}