45656이란 수를 보자.
이 수는 인접한 모든 자리의 차이가 1이다. 이런 수를 계단 수라고 한다.
N이 주어질 때, 길이가 N인 계단 수가 총 몇 개 있는지 구해보자. 0으로 시작하는 수는 계단수가 아니다.
첫째 줄에 N이 주어진다. N은 1보다 크거나 같고, 100보다 작거나 같은 자연수이다.
첫째 줄에 정답을 1,000,000,000으로 나눈 나머지를 출력한다.
1
9
2
17
import java.io.BufferedReader;
import java.io.InputStreamReader;
class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
long mod = 1_000_000_000;
//dp[i][j] -> i(자릿수), j(자릿값)
long[][] dp = new long[N+1][10];
//첫째 자리수는 경우의 수가 하나 뿐
for(int i=1; i<10; i++) {
dp[1][i] = 1;
}
for(int i=2; i<=N; i++) {
//현재 자릿값을 0부터 9까지 탐색
for(int j=0; j<10; j++) {
if(j == 9) {
dp[i][j] = dp[i-1][8] % mod;
} else if (j == 0) {
dp[i][j] = dp[i-1][1] % mod;
} else {
dp[i][j] = (dp[i-1][j-1] + dp[i-1][j+1]) % mod;
}
}
}
long ans = 0;
for(int i=0; i<10; i++) {
ans += dp[N][i];
}
System.out.println(ans % mod);
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
long[] dp = new long[101];
long mod = 1_000_000_000;
dp[1] = 9;
for(int i=2; i<=N; i++) {
dp[i] = (dp[i-1] * 2 - (i-1))% mod;
}
System.out.println(dp[N]);
//N=1 -> 9 * 1 - 0 = 9개
//N=2 -> 9 * 2 - 1 = 17개
//N=3 -> 17 * 2 - 2 = 32개
//N=4 -> 32 * 2 - 3 = 63개
// 10(101) 12(121 123)
// 21(212 210) 23(232 234)
// 32(323 321) 34(343 345)
// ...
// 76 78(789 787)
// 87(878 876) 89(898)
// 98(989 987)
}
}
맨 처음에는 단순히 ‘수학 구현’의 문제로 생각했습니다. 그래도 그 전의 값을 저장해야한다는 점에서 dp를 사용하려고 했구요. 하지만 답을 구현하면서 이정도 답이 실버1 문제일리가 없는데 … 생각이 들었기 때문에 풀면서도 답이 아니겠구나 하는 생각을 했습니다. 그리고 역시나 답은 아니었습니다. 곰곰히 생각해도 답을 찾지 못해서 다른 사람의 풀이를 참고하여 풀었습니다.
문제의 가장 큰 핵심 아이디어는 위와 같습니다. dp를 2차원 배열로 생성하여, 자릿수와 자릿값을 저장해 점화식을 세우는 것입니다. 문제를 차근히 풀어보겠습니다.
dp[3][5] = dp[2][6] + dp[2][4];
만약 3자리 수의 5번째 계단(dp[3][5])이라고 가정을 해봅시다. 3자리수 5번째 계단은 2자리 수 계단의 6번째 계단에서 내려오거나 2자리 수 계단의 4번째에서 올라오는 경우에 3자리수 5번째 계단이 될 것 입니다.
dp[i][j] = dp[i-1][j+1] + dp[i-1][j-1];
이것을 점화식으로 풀면 이렇게 됩니다.
if(j == 9) {
dp[i][j] = dp[i-1][8]; //내려가는 행위
} else if (j == 0) {
dp[i][j] = dp[i-1][1]; //올라가는 행위
} else {
dp[i][j] = (dp[i-1][j-1] + dp[i-1][j+1]); //내려가거나 올라가는 행위
}
계단 수 이기 때문에 위칸(+1), 아래칸(-1) 둘 중 하나만 선택이 가능합니다. 하지만 맨 아래계단(0) 이나 맨 윗 계단(9)는 각각 올라가거나(+1) 내려가는(-1) 행위 밖에 하지 못합니다. 그래서 총 3개의 if 문이 발생됩니다.
핵심 로직 두 가지, (1)dp를 2차원 배열로 구현해 풀어갈 것 (2)맨 위 계단과 맨 아래 계단을 if문으로 나눌 것 만 고려하면 문제가 어렵지 않게 풀립니다. 하지만 이 아이디어를 바로 생각하지 못해 저는 결국 바로 생각하지 못하고 풀이를 참고했습니다.
2차원 dp 배열은 처음 보았습니다. 생각해보면 이차원도 충분히 사용할 수 있는데, 일차원만 있다고 저도 모르게 스스로 생각했던 것 같습니다. 언제나 열린 사고로 문제를 풀도록 해야할 것 같습니다.