Skip to main content

[백준] 11057 오르막 수 (JavaScript)

•3 min•516 words

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

문제 설명

  • 수의 길이 N이 주어졌을 때, 오르막 수의 개수를 구하는 문제
  • 수는 0으로 시작할 수 있다.

예제 입력/출력

  • 입력1

    1
  • 출력1

    10
  • 입력2

    2
  • 출력2

    55
  • 입력3

    3
  • 출력3

    220

제약 조건

  • $1 ≤ N ≤ 1,000$
  • $0 ≤$ 각 자리 수 ≤9≤ 9

문제 풀이

접근1 브루트포스

  • 길이가 N인 모든 숫자를 전부 생성한 뒤, 각 숫자가 오르막 수인지 검사하는 방식
    • 각 자리는 0 ~ 9
    • 총 경우의 수: $10^N$
  • 최악의 경우 $10^{1000}$ 개의 숫자 생성이 필요하기 때문에 현실적으로 불가능

접근2 DP

길이 / 맨뒷자리 수0123456789결과
1111111111110
21098765432155
355453628211510631220
4220165120845635201041715
…
  • 위 표는 길이가 n이고, 맨 마지막 자리가 i인 오르막 수의 개수를 모두 정리한 것이다.
  • 이 표가 어떻게 만들어지는지를 3단계로 나눠서 살펴보자.
    1. 길이가 1인 경우
      • 길이가 1이면 선택할 수 있는 숫자는 0 ~ 9 뿐이다.
      • 한 자리 수는 항상 오르막 수로 어떤 숫자가 오든 경우의 수는 1이다.
      • 이 값이 DP의 시작점(초기값) 이 된다.
    2. 길이가 2인 경우
      • 오르막 수이기 때문에 앞자리 숫자는 뒷자리 숫자보다 작아질 수 없다.
        • 마지막 자리가 0이면 → 앞자리는 0 ~ 9 모두 가능 → 10개
        • 마지막 자리가 1이면 → 앞자리는 1 ~ 9 가능 → 9개
        • …
        • 마지막 자리가 9이면 → 앞자리는 9만 가능 → 1개
    3. 같은 방식으로 계속 누적
      • 이 규칙은 길이가 늘어나도 절대 변하지 않는다.
      • 즉 길이가 n이고 마지막 숫자가 i인 경우의 수는 길이가 n-1이고 마지막 숫자가 i 이상인 모든 경우의 합이다.

1️⃣ DP 테이블 정의

dp[n][i]: 길이가 n인 오르막 수 중, n번째 자리에 숫자 i가 오는 경우의 수
  • n: 수의 길이 ($1 ≤ n ≤ N$)
  • i: 현재 자리의 숫자 ($0 ≤ i ≤ 9$)
  • 수는 0으로 시작할 수 있음.

2️⃣ 초기값 설정

dp[1][i] = 1  (0 ≤ i ≤ 9)
  • 길이가 1인 경우에는, 각 숫자 하나만 선택하면 되므로 모든 경우의 수는 1이다.

3️⃣ 점화식

dp[n][i] = dp[n-1][i] + dp[n-1][i+1] + ... + dp[n-1][9]
  • 오르막 수의 조건상, 현재 자리에 i가 오려면 이전 자리에 오는 숫자는 i 이상이어야 한다.
    • 즉, 이전 자리 숫자는 i ~ 9
    • 해당 경우의 수를 모두 더한다.
Note

❗ 문제 조건에 따라 반드시 더한값은 10007로 나눈 나머지를 사용한다.

4️⃣ 최종 결과 계산

answer = Σ dp[N][i]   (0 ≤ i ≤ 9)
  • 길이가 N인 오르막 수의 총 개수는 마지막 자리에 올 수 있는 모든 숫자를 합한 값이다.
Note

❗ 문제 조건에 따라 반드시 결과값은 10007로 나눈 나머지를 사용한다.

풀이 코드

DP

메모리: 9,984 kB
시간: 156 ms

const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : `${__dirname}/input.txt`;
const input = fs.readFileSync(filePath).toString();

const N = Number(input);
const MOD = 10_007;

// dp[n][i] : n번째 자리에 i가 들어왔을 때 가능한 경우의 수
const dp = Array.from({ length: N + 1 }, () => Array(10).fill(0));

// DP 초기화
dp[1].fill(1);

// DP
for (let n = 2; n <= N; n++) {
  for (let i = 0; i <= 9; i++) {
    let sum = 0;
    for (let j = i; j <= 9; j++) {
      sum = (sum + dp[n - 1][j]) % MOD;
    }
    dp[n][i] += sum;
  }
}

// 결과
let answer = 0;
for (let i = 0; i <= 9; i++) {
  answer = (answer + dp[N][i]) % MOD;
}

console.log(answer);