지원이에게 2진 수열을 가르쳐 주기 위해, 지원이 아버지는 그에게 타일들을 선물해주셨다.
그리고 이 각각의 타일들은 0 또는 1이 쓰여 있는 낱장의 타일들이다.
어느 날 짓궂은 동주가 지원이의 공부를 방해하기 위해
0이 쓰여진 낱장의 타일들을 붙여서 한 쌍으로 이루어진 00 타일들을 만들었다.
결국 현재 1 하나만으로 이루어진 타일 또는 한 쌍의 00타일들만이 남게 되었다.
그러므로 지원이는 타일로 더 이상 크기가 N인 모든 2진 수열을 만들 수 없게 되었다.
예를 들어, N=1일 때 1만 만들 수 있고, N=2일 때는 00, 11을 만들 수 있다.
(01, 10은 만들 수 없게 되었다.)
또한 N=4일 때는 0011, 0000, 1001, 1100, 1111 등 총 5개의 2진 수열을 만들 수 있다.
우리의 목표는 N이 주어졌을 때 지원이가 만들 수 있는 모든 가짓수를 세는 것이다.
단 타일들은 무한히 많은 것으로 가정하자.
지원이가 갖고있는 타일의 종류는 1
타일과 0이 두개 붙여진 00
타일이다.
N=1일 때 1만 만들 수 있고, N=2일 때는 00, 11을 만들 수 있다.
(01, 10은 만들 수 없게 되었다.)
N=4일 때는 0011, 0000, 1001, 1100, 1111 등 총 5개의 2진 수열을 만들 수 있다.
N이 주어졌을 때 지원이가 만들 수 있는 모든 가짓수를 세는 것이다. 단 타일들은 무한히 많은 것으로 가정한다.
입력
첫 번째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 1,000,000)
출력
첫 번째 줄에 지원이가 만들 수 있는 길이가 N인 모든 2진 수열의 개수를 15746으로 나눈 나머지를 출력한다.
입출력 예시
나는 먼저 N이 6일때까지 만들 수 있는 2진수열의 가지 수를 표로 그려봤다.
(사실 더 많이 그려봄)
N 개수 | 만들 수 있는 2진 수열 | 가지 수 |
---|---|---|
1 | 1 | 1 |
2 | 00, 11 | 2 |
3 | 001, 100, 111 | 3 |
4 | 0000, 0011, 1001, 1100, 1111 | 5 |
5 | 00001, 00100, 00111, 10000, 10011, 11001, 11100, 11111 | 8 |
6 | 000000, 000011, 001100, 110000, 001001, 100001, 100100, 001111, 110011, 111100, 100111, 111100, 111111 | 13 |
위 표에서 규칙성이 보이는데이렇게 쭉 그리다보면 가지수가 규칙성을 보이는 것을 알아챌 수 있다.
f(N) = f(N-1) + f(N-2)
ex
f(3) = f(2) + f(1) = 2 + 1 = 3
f(4) = f(3) + f(2) = 3 + 2 = 5
f(5) = f(4) + f(3) = 5 + 3 = 8
f(6) = f(5) + f(4) = 8 + 5 = 13
위 규칙은 피보나치 수
인 것을 확인할 수 있다.
public class Main {
public static void main(String[] args) {
int N = 4; // 2진 수열의 길이 N
int[] tile = new int[num + 1]; // tile 배열 초기화
System.out.print(dp(num, tile));
}
public static int dp(int i, int[] tile) {
if (i <= 2) return i; // 기저 조건: F(1) = 1, F(2) = 2
if (tile[i] == 0) tile[i] = (dp(i - 1, tile) + dp(i - 2, tile)) % 15746; // 모듈러 연산 유지
return tile[i];
}
}
1️⃣ 입력 처리
사용자로부터 N 값을 입력받아 처리
N 은 1 ≤ N ≤ 1,000,000 로 제한
(입출력 예시로 4로 초기화 설정함)
2️⃣ 동적 계획법 배열 초기화
tile
배열은 이전에 계산한 값을 저장하기 위해 사용
tile[i]는 F(i) 값을 저장
3️⃣ 피보나치 계산 로직
기저 조건
F(1)=1, F(2)=2로 설정
중복 계산 방지
이미 계산된 값은 tile[i]에서 바로 반환
점화식 적용
계산되지 않은 경우(0인경우), F(n)=F(n−1)+F(n−2)로 값을 계산하고 tile[i]에 저장
(15746을 나눈 나머지 값으로 저장)
시간 복잡도
공간 복잡도
dp
배열은 O(n) 의 공간을 차지한다.import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int num = Integer.parseInt(br.readLine());
int[] tile = new int[num + 1];
System.out.print(dp(num, tile));
}
public static int dp(int i, int[] tile) {
if (i <= 2) return i;
if (tile[i] == 0) tile[i] = (dp(i - 1, tile) + dp(i - 2, tile)) % 15746;
return tile[i];
}
}