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; } }