(C++) 백준 11057번 - 오르막 수

코딩너구리·2025년 12월 18일

코딩 문제 풀이

목록 보기
134/266

https://www.acmicpc.net/problem/11057

문제

> 오르막 수는 수의 자리가 오름차순을 이루는 수를 말한다. 
> 이때, 인접한 수가 같아도 오름차순으로 친다.

> 예를 들어, 2234와 3678, 11119는 오르막 수이지만,
2232, 3676, 91111은 오르막 수가 아니다.

> 수의 길이 N이 주어졌을 때, 오르막 수의 개수를 구하는 프로그램을 작성하시오. 
> 수는 0으로 시작할 수 있다.

접근

dp를 이차원 벡터로 선언하고 행을 자릿수, 열을 그 수로 끝나는 수라고 잡고 표를 그려보면 아래와같다.
1자리수 일 땐 끝에 뭐가오던 1가지씩 가능하므로 전부 1이고
자릿수 상관없이 0으로 끝나는 수도 1가지씩만 가능하다(0,000...)
이제 2,1을 보면 2자리수인데 1로 끝나는 수를 말하고 이는 01,11 이렇게 두개가있다. 즉 다시 말하면 2자리 인데 1로끝나는 거니까 ?1로 수를 잡고 ?에는 1보다 작은 수만 올 수 있다.
그럼 표에서 -1행에서 1보다 작은 애들의 수를 더한 값이된다.
그래서 2,2는 1,0과 1,1과 1,2을 더한 3이 되는 것이다.
이제 3,1을 보면 2,0과 2,1을 더한 값이된다.
3,2는 2,0과 2,1과 2,2를 더한 값이다.
둘 이 겹치는 부분이 생긴다. 2,0과 2,1
즉, 3,2는 3,1과 2,2의 합이라고도 할 수 있는 것이다.
따라서 이를 수식으로 써보면 dp(i)(j) = dp(i)(j-1) + dp(i-1)(j)라고 할 수 있다.

문제해결

> 각 자릿수와 끝나는 수 별로 가능한 경우를 저장할 이차원 벡터 dp를 만든다. 
> 1,?와 ?,0은 모두 1개씩만 가능하므로 이를 1로초기화 해준다.
> 2자릿수 부터 1~9까지 끝나는 수를 위에서 유도한 공식으로 구한다.
문제에서 10007을 나눈 나머지를 따지라고 했으므로 dp값을 구할 때마다 이를 연산해준다.
> 각 자릿수의 총 가능한 경우의 수는 0부터 9일 때까지의 모든 경우를 더해준 것이므로 이를 다 더해준다.
더해주면서 mod10007연산을 해주고 최종 결과를 출력한다.

코드

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;

int N;
vector<vector<int>> dp;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);

	cin >> N;
	dp.resize(N + 1, vector<int>(10));
	for (int i = 1; i <= N; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (i != 1 && j != 0) continue;
			dp[i][j] = 1;
		}
	}
	
	for (int i = 2; i <= N; i++)
	{
		for (int j = 1; j < 10; j++)
		{
			dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % 10007;
		}
	}
	int rst = 0;
	for (auto a : dp[N])
	{
		rst += a;
		rst %= 10007;
	}
	cout << rst << '\n';
}

후기

처음에 재귀로 했는데 시간초과가 났다.
1000자리수가들어오면 이를 0부터9까지 10가지를 각 자리마다 해줘야하므로 시간초과가 날거같긴 헀다.
그래서 dp로접근했다.
공식을 유도하는게 빡세긴 했지만 원리를 알면 어찌저찌 구해진다.

0개의 댓글