일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 백준2141
- 생활코딩
- 백준2533
- BOJ14719
- BOJ1753
- github_actions
- BOJ11729
- BOJ20444
- BOJ2805
- BFS
- BOJ14501
- html
- 백트래킹
- 백준 #BOJ #1697
- 재귀
- 이분탐색
- 색종이와가위
- BOJ1931
- boj
- BOJ11404
- BOJ11066
- 백준2110
- 프로그래머스 #무지의먹방라이브 #C++
- 백준11404
- DP
- 1520내리막길
- 백준
- BOJ2629
- BOJ2110
- BOJ9663
- Today
- Total
poksul_log
# 10844. 쉬운 계단 수 본문
관련 알고리즘 : DP
문제 링크 : https://www.acmicpc.net/problem/10844
10844번: 쉬운 계단 수
첫째 줄에 정답을 1,000,000,000으로 나눈 나머지를 출력한다.
www.acmicpc.net
문제 풀이
n자리 숫자 중 계단수(각 자릿수마다 있는 수의 차이가 1인 수)의 개수를 구하는 문제이다.
'일의 자리 숫자가 무엇인가' 와 'n(자리수)'를 기준으로 dp 식을 세우면 문제를 해결할 수 있다.
n=2인 경우를 예를 들어 생각해보자.
일의 자리 | 십의 자리 | 개수 |
0 | 1 | 1 |
1 | 2 | 1 |
2 | 1, 3 | 2 |
3 | 2, 4 | 2 |
4 | 3, 5 | 2 |
5 | 4, 6 | 2 |
6 | 5, 7 | 2 |
7 | 6, 8 | 2 |
8 | 7, 9 | 2 |
9 | 8 | 1 |
십의 자리 숫자가 일의 자리 숫자가 무엇이느냐에 따라 영향을 받는 것을 알 수 있다.
0, 1, 9를 제외한 나머지 숫자들은 모두 (해당숫자-1), (해당숫자+1) 이렇게 2가지씩 경우가 존재한다.
그렇다면, 위를 토대로 n=3일 경우를 생각해보자.
일의 자리 | 백의 자리 + 십의 자리 + (일의 자리) |
0 | n=2일때 중 일의 자리가 1인 수 + (일의 자리 0) |
1 | n=2일때 중 일의 자리가 0 / 2인 수 + (일의 자리 1) |
2 | n=2일때 중 일의 자리가 1 / 3인 수 + (일의 자리 2) |
3 | n=2일때 중 일의 자리가 2 / 4인 수 + (일의 자리 3) |
4 | n=2일때 중 일의 자리가 3 / 5인 수 + (일의 자리 4) |
5 | n=2일때 중 일의 자리가 4 / 6인 수 + (일의 자리 5) |
6 | n=2일때 중 일의 자리가 5 / 7인 수 + (일의 자리 6) |
7 | n=2일때 중 일의 자리가 6 / 8인 수 + (일의 자리 7) |
8 | n=2일때 중 일의 자리가 7 / 9인 수 + (일의 자리 8) |
9 | n=2일때 중 일의 자리가 8인 수 + (일의 자리 9) |
즉, n자리수의 계단수 개수는 일의 자리와 (n-1)자리수의 계단수 개수에 영향을 받는 것을 알 수 있다.
따라서, 점화식을 세우면 다음과 같다.
d[i][j] : i의 자리수를 갖는, 일의 자리가 j인 계단수의 개수
j = 0일 시, d[i][0] = d[i-1][1]
j = 1~8일 시, d[i][j] = d[i-1][j-1] + d[i-1][j+1]
j = 9일 시, d[i][9] = d[i-1][8]
※ 주의할 점(mod 연산 시)
처음에는 d[n][0~9]값들을 모두 구한 후, 이를 다 합쳐 res 변수에 저장하고
최종적으로 결과를 출력할 때 mod값( 1,000,000,000 ) 으로 나눠주었다.
그러나 백준 저지에서 계속 틀렸다고 나왔다. 내 ide에서는 결과값이 멀쩡하게 잘 나오는데 말이다!
검색해보니, 모든 연산을 마치고 마지막으로 mod 값으로 나눠서 한큐에 해결하고자 하면
자료형의 한계 범위를 넘어가서 오버플로우가 발생할 수 있다고 한다.
따라서 이와 같은 문제를 해결하기 위해서는 '모듈러 연산의 분배법칙'을 따른다.
📍모듈러 연산의 분배법칙
1. (a+b) mod p = (a mod p + b mod p) mod p
2. (a×b) mod p = (a mod p × b mod p) mod p
3. (a−b) mod p = (a mod p − b mod p) mod p
즉, 중간중간 모듈러 연산을 해 줘야 이후 오버플로우 발생을 예방할 수 있다.
C++ 코드
#include <iostream>
using namespace std;
#define mod 1000000000
int n;
int d[101][10]; // d[i][j]일 때, i자리 숫자 중 일의자리 수가 j인 경우의 수
int res = 0;
void dp()
{
for(int i=1; i<10; i++)
d[1][i] = 1;
for(int i=2; i<=n; i++)
{
for(int j=0; j<10; j++)
{
if(j==0)
d[i][0] = d[i-1][j+1];
else if(j==9)
d[i][9] = d[i-1][j-1];
else
d[i][j] = d[i-1][j-1] + d[i-1][j+1];
d[i][j] %= mod;
}
}
}
int main()
{
cin >> n;
dp();
for(int i=0; i<10; i++)
{
res = (res+d[n][i]) % mod;
}
cout << res;
return 0;
}
'Coding Test > BOJ' 카테고리의 다른 글
# 3273. 두 수의 합 (0) | 2023.07.23 |
---|---|
# 2667. 단지번호붙이기 (0) | 2023.06.25 |
# 7576. 토마토 (0) | 2023.04.02 |
# 9205. 맥주 마시면서 걸어가기 (0) | 2023.03.26 |
# 2573. 빙산 (0) | 2023.03.12 |