https://www.acmicpc.net/problem/2011
쉬운듯하지만 신경쓸게 있고, 구현 과정에서 실수하기 좋은(헷갈리는..) 부분이 많아서 푸는데 시간이 좀 걸렸다.
우선 dp로 풀 수 있는 문제이다. 25114가 주어졌을 때, 먼저 2를 만드는 경우부터 25, 251, ... , 25114를 만드는 경우까지 생각해보자.
- 2 -> dp[1] = 1
- 2
- 25 -> dp[2] = 2
- 2 + 5
- 25
- 251 -> dp[3] = 2
- 2 + 5 + 1
- 25 + 1
- 2511 -> dp[4] = 4
- 2 + 5 + 1 + 1
- 25 + 1 + 1
- 2 + 5 + 11
- 25 + 11
- 25114 -> dp[5] = 6
- 2 + 5 + 1 + 1 + 4
- 25 + 1 + 1 + 4
- 2 + 5 + 11 + 4
- 25 + 11 + 4
- 2 + 5 + 1 + 14
- 25 + 1 + 14
이렇게 직접 써가며 풀어보면, 규칙이 보인다. 251의 경우, 새로 추가된 수가 1이고, 1이 추가됨으로써 생성된 수는 51(251)이다. 그런데 51은 암호가 될 수 없다. 따라서 251은 25로 만들었던 암호에 1만 더한 값이다. 즉, dp[i] = dp[i - 1]이다.
반면 2511의 경우, 새로 추가된 수가 1이고, 1이 추가됨으로써 생성된 수는 11(2511)이다. 11은 암호가 될 수 있다. 따라서 2511은 251로 만들었던 암호에 1을 더한 경우와 25로 만들었던 암호에 11을 더한 경우이다. 즉, dp[i] = dp[i - 1] + dp[i - 2]이다.
결론적으로 점화식은 다음과 같다.
* 새로 만들어지는 수가 1~26 범위 내이면, dp[i] = dp[i - 1] + dp[i - 2]
* 새로 만들어지는 수가 1~26 범위 밖이면, dp[i] = dp[i - 1]
그리고 0이 포함되는 경우를 주의해야 한다.
- 특정 자리수 i의 값이 0이면, 무조건 그 앞자리와 합친 값으로 암호를 생성해야 한다. 그리고 이때 합친 값의 범위도 체크해줘야 한다.(10 이상 && 30 미만)
- 10인 경우, 1 + 0이 될 수 없고 무조건 앞 자리와 합친 10만 될 수 있다.
- 30인 경우, 30은 암호 범위를 벗어나므로 암호를 해석할 수 없어 0을 출력해야 한다.
- 만약 특정 자리수 i의 값이 0이 아니더라도, 그 앞자리와 합칠 때 앞자리가 0인 경우를 고려해야 한다. (합친 값의 범위 = 10이상 && 26 이하)
- 이어지는 숫자가 11인 경우, 범위 내의 값이므로 암호가 될 수 있다.
- 이어지는 숫자가 01인 경우, 두 수를 합칠 수 없다.
- 이어지는 숫자가 41인 경우, 범위 밖의 값이므로 암호가 될 수 없다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
public static void main(String[] args) throws IOException {
final int mod = 1000000;
String code = br.readLine();
int[] dp = new int[code.length() + 1];
dp[0] = 1;
// dp[i]의 값 채우기
for (int i = 1; i <= code.length(); i++) {
int num = code.charAt(i - 1) - '0';
if (i == 1) {
// 제일 첫 번째 숫자가 0이면 해석 불가!
if (num == 0) {
System.out.println(0);
return;
} else {
dp[i] = 1;
}
continue;
}
// 이번 숫자가 0인 경우, 앞자리와 합치기
if (num == 0) {
// 이번 숫자의 앞 숫자가 범위 밖이면 해석 불가!
int prev = code.charAt(i - 2) - '0';
if (prev <= 0 || prev >= 3) {
System.out.println(0);
return;
}
dp[i] = dp[i - 2] % mod;
} else {
int prev = code.charAt(i - 2) - '0';
int connectedNum = prev * 10 + num;
// 이어지는 숫자가 범위 안 -> dp[i] = dp[i - 1] + dp[i - 2]
if (connectedNum >= 10 && connectedNum <= 26) {
dp[i] = (dp[i - 1] + dp[i - 2]) % mod;
}
// 이어지는 숫자가 범위 밖 -> dp[i] = dp[i - 1]
else {
dp[i] = dp[i - 1] % mod;
}
}
}
System.out.println(dp[code.length()]);
}
}
'CS > Algorism' 카테고리의 다른 글
[백준] 1941. 소문난 칠공주 (0) | 2024.07.03 |
---|---|
[백준] 7570. 줄 세우기 (0) | 2024.07.01 |
[2022 KAKAO TECH INTERNSHIP] 코딩 테스트 공부 (0) | 2024.06.21 |
[2023 KAKAO BLIND RECRUITMENT] 미로 탈출 명령어 (0) | 2024.06.21 |
[2024 KAKAO WINTER INTERNSHIP] n + 1 카드게임 (0) | 2024.06.20 |