λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

Algorithm

[Algorithm] ν•©λΆ„ν•΄ (λ°±μ€€ - 2225)

문제

0λΆ€ν„° NκΉŒμ§€μ˜ μ •μˆ˜ K개λ₯Ό λ”ν•΄μ„œ κ·Έ ν•©μ΄ N이 λ˜λŠ” κ²½μš°μ˜ μˆ˜λ₯Ό κ΅¬ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.

λ§μ…ˆμ˜ μˆœμ„œκ°€ 바뀐 κ²½μš°λŠ” λ‹€λ₯Έ 경우둜 μ„Όλ‹€(1+2와 2+1은 μ„œλ‘œ λ‹€λ₯Έ 경우). λ˜ν•œ ν•œ 개의 수λ₯Ό μ—¬λŸ¬ 번 μ“Έ μˆ˜λ„ μžˆλ‹€.

μž…λ ₯

첫째 쀄에 두 μ •μˆ˜ N(1 ≤ N ≤ 200), K(1 ≤ K ≤ 200)κ°€ μ£Όμ–΄μ§„λ‹€.

좜λ ₯

첫째 μ€„에 λ‹΅μ„ 1,000,000,000으둜 λ‚˜λˆˆ λ‚˜λ¨Έμ§€λ₯Ό μΆœλ ₯ν•œλ‹€.

μž…μΆœλ ₯ 예

예제 μž…λ ₯ 예제 μΆœλ ₯
20 2 21

풀이

μ „ν˜•μ μΈ DP λ¬Έμ œμ΄λ‹€. μ΅œμ’…μ μœΌλ‘œ 합이 n이 λ˜λŠ” λͺ¨λ“  경우의 수λ₯Ό κ³„μ‚°ν•˜κΈ° μœ„ν•΄μ„œλŠ” 이전에 λ§Œλ“€μ—ˆλ˜ 값을 μ΄μš©ν•˜λ©΄μ„œ 계산할 수 μžˆλ‹€. 점화식은 λ‹€μŒκ³Ό κ°™λ‹€.

 

DP[i][j] = j개λ₯Ό μ‚¬μš©ν•΄μ„œ iλ₯Ό λ§Œλ“œλŠ” 경우의 수

 

λ§Œμ•½ 10(n)λ₯Ό 3(k)개의 수λ₯Ό λ”ν•΄μ„œ λ§Œλ“€μ–΄μ•Ό ν•  λ•Œ λ‹€μŒκ³Ό 같이 κ³„μ‚°ν•œλ‹€.

  • 0개 숫자λ₯Ό μ‚¬μš©ν•˜λŠ” 경우 λ§Œλ“€ 수 μžˆλŠ” μˆ˜κ°€ μ—†μœΌλ―€λ‘œ λͺ¨λ‘ 0 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0 ]
  • 1개 숫자λ₯Ό μ‚¬μš©ν•˜λŠ” 경우 λ§Œλ“€μ–΄μ•Ό ν•˜λŠ” μˆ«μžκ°€ κ³§ μ΄μš©ν•  숫자둜 λͺ¨λ‘ 1 [ 1, 2, 3, 4,  5, 6, 7, 8, 9, 10, 11 ]

μ—¬κΈ°κΉŒμ§€κ°€ μ΄ˆκΈ°ν™” 단계이닀. 이제 2개 숫자λ₯Ό μ‚¬μš©ν•΄μ„œ 각 숫자(1~10)을 λ§Œλ“œλŠ”λ° μ΄λŠ” μ΄μ „μ˜ DPλ₯Ό μ΄μš©ν•˜κΈ° μ‹œμž‘ν•œλ‹€. 예λ₯Ό λ“€μ–΄ 10을 숫자 λ‘κ°œλ₯Ό μ΄μš©ν•΄μ„œ λ§Œλ“œλŠ” κ²½μš°μ—λŠ” λ‹€μŒκ³Ό 같은 κ²½μš°λ“€μ΄ μžˆλ‹€.

 

  • DP[1][1] (숫자 1개λ₯Ό μ΄μš©ν•΄μ„œ 1을 λ§Œλ“œλŠ” 경우) + 9
  • DP[1][2] (숫자 1개λ₯Ό μ΄μš©ν•΄μ„œ 2을 λ§Œλ“œλŠ” 경우) + 8
  • DP[1][3] (숫자 1개λ₯Ό μ΄μš©ν•΄μ„œ 3을 λ§Œλ“œλŠ” 경우) + 7
  • DP[1][4] (숫자 1개λ₯Ό μ΄μš©ν•΄μ„œ 4을 λ§Œλ“œλŠ” 경우) + 6
  • DP[1][5] (숫자 1개λ₯Ό μ΄μš©ν•΄μ„œ 5을 λ§Œλ“œλŠ” 경우) + 5
  • DP[1][6] (숫자 1개λ₯Ό μ΄μš©ν•΄μ„œ 6을 λ§Œλ“œλŠ” 경우) + 4
  • DP[1][7] (숫자 1개λ₯Ό μ΄μš©ν•΄μ„œ 7을 λ§Œλ“œλŠ” 경우) + 3
  • DP[1][8] (숫자 1개λ₯Ό μ΄μš©ν•΄μ„œ 8을 λ§Œλ“œλŠ” 경우) + 2
  • DP[1][9] (숫자 1개λ₯Ό μ΄μš©ν•΄μ„œ 9을 λ§Œλ“œλŠ” 경우) + 1
  • DP[1][10] (숫자 1개λ₯Ό μ΄μš©ν•΄μ„œ 10을 λ§Œλ“œλŠ” 경우) + 0

이 λ‹€μŒμœΌλ‘œ 숫자 2개λ₯Ό μ΄μš©ν•΄μ„œ 각 숫자λ₯Ό λ§Œλ“œλŠ” κ²½μš°λŠ” μœ„μ™€ λ™μΌν•˜κ²Œ λ‹€μŒκ³Ό κ°™λ‹€.

  • DP[2][1] (숫자 2개λ₯Ό μ΄μš©ν•΄μ„œ 1을 λ§Œλ“œλŠ” 경우) + 9
  • DP[2][2] (숫자 2개λ₯Ό μ΄μš©ν•΄μ„œ 2을 λ§Œλ“œλŠ” 경우) + 8
  • DP[2][3] (숫자 2개λ₯Ό μ΄μš©ν•΄μ„œ 3을 λ§Œλ“œλŠ” 경우) + 7
  • DP[2][4] (숫자 2개λ₯Ό μ΄μš©ν•΄μ„œ 4을 λ§Œλ“œλŠ” 경우) + 6
  • DP[2][5] (숫자 2개λ₯Ό μ΄μš©ν•΄μ„œ 5을 λ§Œλ“œλŠ” 경우) + 5
  • DP[2][6] (숫자 2개λ₯Ό μ΄μš©ν•΄μ„œ 6을 λ§Œλ“œλŠ” 경우) + 4
  • DP[2][7] (숫자 2개λ₯Ό μ΄μš©ν•΄μ„œ 7을 λ§Œλ“œλŠ” 경우) + 3
  • DP[2][8] (숫자 2개λ₯Ό μ΄μš©ν•΄μ„œ 8을 λ§Œλ“œλŠ” 경우) + 2
  • DP[2][9] (숫자 2개λ₯Ό μ΄μš©ν•΄μ„œ 9을 λ§Œλ“œλŠ” 경우) + 1
  • DP[2][10] (숫자 2개λ₯Ό μ΄μš©ν•΄μ„œ 10을 λ§Œλ“œλŠ” 경우) + 0

이λ₯Ό μ‚¬μš©ν•  숫자의 수인 k번 λ°˜λ³΅ν•˜κ³  각각 반볡문이 ν•œ 번 더 μˆ˜ν–‰λ˜λŠ”λ°  n번 λ°˜λ³΅ν•˜κ²Œ λœλ‹€. λͺ¨λ“  과정을 거치게 되면 DP[k][n]이 닡이 λœλ‹€. μΆ”κ°€μ μœΌλ‘œ 이전 값을 μ΄μš©ν•΄μ„œ ν˜„μž¬ 값을 ꡬ할 λ•Œ 문제 쑰건 쀑 μ£Όμ˜ν•΄μ•Ό ν•  사항이 μžˆλŠ”λ° κ³„μ‚°ν• λ•Œλ§ˆλ‹€  1,000,000,000으둜 λ‚˜λˆˆ λ‚˜λ¨Έμ§€λ₯Ό μ €μž₯ν•΄μ•Ό ν•œλ‹€. λ§ˆμ§€λ§‰μ— ν•œ 번만 ν•΄μ£Όκ²Œ 되면 계산 κ³Όμ • 쀑 값이 ν—ˆμš©κ°€λŠ₯ ν•œ 숫자λ₯Ό λ„˜κ²¨ 계산이 λΆˆκ°€λŠ₯ν•΄μ§€λŠ” κ²½μš°λ„ μ‘΄μž¬ν•œλ‹€. λ˜λŠ” BigIntλ₯Ό μ‚¬μš©ν•΄μ„œ κ³„μ‚°ν•˜κ³  λ§ˆμ§€λ§‰μ— ν•œ 번만 계산할 수 μžˆλ‹€.

 

μ½”λ“œ

const fs = require("fs");
const filePath =
  process.platform === "linux" ? "/dev/stdin" : "./testcase/2225.txt";

const inputs = fs.readFileSync(filePath).toString().trim().split("\n");

const [n, k] = inputs[0].split(" ").map(Number);

const dp = [...Array(k + 1)].map((_) => new Array(n + 1).fill(0));
for (let i = 0; i <= n; i++) dp[1][i] = 1;

for (let i = 2; i <= k; i++) {
  for (let j = 0; j <= n; j++) {
    for (let jj = 0; jj <= n; jj++) {
      if (j + jj > n) continue;
      dp[i][j + jj] = (dp[i][j + jj] + dp[i - 1][j]) % 1000000000;
    }
  }
}
console.log(dp[k][n]);