fee-fi-fo-fum
λ°˜μ‘ν˜•

문제

μ •μˆ˜ 4λ₯Ό 1, 2, 3의 ν•©μœΌλ‘œ λ‚˜νƒ€λ‚΄λŠ” 방법은 총 3κ°€μ§€κ°€ μžˆλ‹€. 합을 λ‚˜νƒ€λ‚Ό λ•ŒλŠ” 수λ₯Ό 1개 이상 μ‚¬μš©ν•΄μ•Ό ν•œλ‹€. 단, 같은 수λ₯Ό 두 번 이상 μ—°μ†ν•΄μ„œ μ‚¬μš©ν•˜λ©΄ μ•ˆ λœλ‹€.

  • 1+2+1
  • 1+3
  • 3+1

μ •μˆ˜ n이 μ£Όμ–΄μ‘Œμ„ λ•Œ, n을 1, 2, 3의 ν•©μœΌλ‘œ λ‚˜νƒ€λ‚΄λŠ” λ°©λ²•μ˜ 수λ₯Ό κ΅¬ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.

## μž…λ ₯

첫째 쀄에 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ˜ 개수 Tκ°€ μ£Όμ–΄μ§„λ‹€. 각 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λŠ” ν•œ μ€„λ‘œ 이루어져 있고, μ •μˆ˜ n이 μ£Όμ–΄μ§„λ‹€. n은 μ–‘μˆ˜μ΄λ©° 100,000보닀 μž‘κ±°λ‚˜ κ°™λ‹€.

## 좜λ ₯

각 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ§ˆλ‹€, n을 1, 2, 3의 ν•©μœΌλ‘œ λ‚˜νƒ€λ‚΄λŠ” λ°©λ²•μ˜ 수λ₯Ό 1,000,000,009둜 λ‚˜λˆˆ λ‚˜λ¨Έμ§€λ₯Ό 좜λ ₯ν•œλ‹€.

μ‹œκ°„ μ œν•œ λ©”λͺ¨λ¦¬ μ œν•œ 제좜 μ •λ‹΅ 맞힌 μ‚¬λžŒ μ •λ‹΅ λΉ„μœ¨
1 초 (μΆ”κ°€ μ‹œκ°„ μ—†μŒ) 512 MB 26395 8918 6250 30.858%

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

풀이

μ•Œκ³ λ¦¬μ¦˜ 흐름

이문제둜 ν•œμ°Έμ„ κ³ λ―Όν–ˆλ‹€... dpλ₯Ό μ‚¬μš©ν•΄μ„œ 1차원 배열을 λ§Œλ“€κ³  아무리 생각을 해봐도 μ•ˆν’€λ¦¬λŠ” 것이닀. λ‚΄κ°€ 고민을 ν•˜λ‹€κ°€ μ•ˆν’€λ Έλ˜ 뢀뢄이 λ§Œμ•½ 3일 경우 1+1+1, 1+2, 3 μ΄λ ‡κ²Œ 3κ°€μ§€μ˜ κ²½μš°κ°€ 생기고, 제일 λ’·μžλ¦¬κ°€ 1μΌλ•Œ, 2μΌλ•Œ, 3μΌλ•Œλ₯Ό κ΅¬λΆ„μ§€μ–΄μ£ΌλŠ” 뢀뢄을 μ–΄λ–»κ²Œ κ΅¬ν˜„ν• μ§€ λ„μ €νžˆ 감이 μ•ˆμ™”λ‹€. κ·Έλž˜μ„œ μ°Ύμ•„λ³΄λ‹ˆ... μ˜€λ§ˆκ°“ μ§„μ§œ μ‚¬λžŒλ“€ λ˜‘λ˜‘ν•΄πŸ˜‚

자그럼 문제λ₯Ό ν’€μ–΄λ³΄μž!

μ΄λ¬Έμ œλŠ” 일단 DP와 2차원 배열을 μ‚¬μš©ν•΄μ•Όν•œλ‹€.

DP λ¬Έμ œμ΄λ―€λ‘œ λ¨Όμ € 곡톡점을 μ°Ύμ•„ λ‚΄λŠ”κ²ƒμ΄ μ€‘μš”ν•˜λ‹€. 문제λ₯Ό μž‘μ€ λ‹¨μœ„λΆ€ν„° 천천히 ν›‘μ–΄ λ³΄μ•˜λ‹€.

1 > 1
2 > 1+1, 2
3 > 1+1+1, 2+1, 1+2, 3
4 > (1+1+1+1, 2+1+1, 1+2+1, 3+1), (1+1+2, 2+2), (1+3)

이정도면 이제 μ–΄λŠμ •λ„ 곡톡점이 λ³΄μ—¬μ•Όν•œλ‹€.

  • 4λ₯Ό λ§Œλ“€λ•Œ, 3을 λ§Œλ“œλŠ” 경우 +1
  • 4λ₯Ό λ§Œλ“€λ•Œ, 2λ₯Ό λ§Œλ“œλŠ” 경우 +2
  • 4λ₯Ό λ§Œλ“€λ•Œ, 1을 λ§Œλ“œλŠ” 경우 +3
    (μ—¬κΈ°μ—μ„œ 2λ²ˆμ΄μƒ μ€‘λ³΅λ˜λŠ” 뢀뢄을 μ œκ±°ν•˜κ³  dp에 κΈ°λ‘ν•˜λ©΄ λ˜κ² κ΅¬λ‚˜.)

이λ₯Ό λ°”νƒ•μœΌλ‘œ dpλ₯Ό λ‚˜νƒ€λ‚΄λ³΄λ©΄,

dp[i][j]    // i: μž„μ˜μ˜ μ •μˆ˜, j: λ§μ…ˆμ΄ j둜 끝남

μ΄λ ‡κ²Œ 보면 λ˜κ² λ‹€. 그럼 μ˜ˆμ‹œλ₯Ό λ“€μ–΄λ³΄μž.

3을 λ§Œλ“œλŠ” 경우

  • 1+1+1 => dp[3][1] = 1
  • 1+2 => dp[3][2] = 1
  • 2+1 => dp[3][1] = 1
  • 3 => dp[3][3] = 1

5λ₯Ό λ§Œλ“œλŠ” 경우

5λ₯Ό λ§Œλ“œλŠ” 경우λ₯Ό μžμ„Έν•˜κ²Œ μ•Œμ•„λ³΄μž.

5λ₯Ό 1, 2 ,3 의 ν•©μœΌλ‘œ λ‚˜νƒ€λ‚΄λ³΄μž.
2λ₯Ό λ§Œλ“œλŠ” κ²½μš°μ— 3을 λ”ν•˜κ³ ,
3을 λ§Œλ“œλŠ” κ²½μš°μ— 2λ₯Ό λ”ν•˜κ³ ,
4λ₯Ό λ§Œλ“œλŠ” κ²½μš°μ— 1을 λ”ν•˜λ©΄ 5κ°€ 될것이닀.
(μ΄λ•Œ 같은 수λ₯Ό 2번 μ—°μ†μœΌλ‘œ μ‚¬μš©ν• μˆ˜λŠ” μ—†λ‹€. 즉, 이전에 μ‚¬μš©ν•œ 값은 μ œκ±°ν•œλ‹€.)

1) 5λ₯Ό λ§Œλ“œλŠ” μˆ˜μ‹μ€‘μ—
1둜 λλ‚˜λŠ” μˆ˜μ‹(λ§ˆμ§€λ§‰μ— 1을 λ”ν•΄μ£ΌλŠ” 경우)은
4λ₯Ό λ§Œλ“œλŠ” μˆ˜μ‹μ—μ„œ 2둜 λλ‚˜λŠ” 것에 1λ₯Ό λ”ν•˜λŠ”κ²ƒ,
4λ₯Ό λ§Œλ“œλŠ” μˆ˜μ‹μ€‘μ—μ„œ 3으둜 λλ‚˜λŠ” 것에 1을 λ”ν•˜λŠ” 것이닀.
(같은 수 연속 2λ²ˆμ€ μ•ˆλ˜κΈ° λ•Œλ¬Έμ— 1둜 λλ‚˜λŠ” 것을 μ œμ™Έν•œλ‹€.)
이λ₯Ό λ‚˜νƒ€λ‚΄λ³΄λ©΄ μ•„λž˜μ™€ κ°™λ‹€.

dp[5][1] = dp[4][2] + dp[4][3];

// 이것을 μΌλ°˜ν™” ν•˜λ©΄ μ•„λž˜μ™€ κ°™λ‹€.

dp[n][1] = dp[n-1][2] + dp[n-1][3];

2) 2λ₯Ό λ”ν•˜λŠ” 경우λ₯Ό μ‚΄νŽ΄λ³΄μž
λ§ˆμ§€λ§‰μ— 2λ₯Ό λ”ν•΄μ£ΌλŠ” κ²½μš°λŠ”,
3을 λ§Œλ“œλŠ” μˆ˜μ‹μ—μ„œ 1둜 λλ‚˜λŠ” 것에 2λ₯Ό λ”ν•˜λŠ”κ²ƒ,
3을 λ§Œλ“œλŠ” μˆ˜μ‹μ—μ„œ 3으둜 λλ‚˜λŠ” 것에 2λ₯Ό λ”ν•˜λŠ” 것이닀.
(이것 λ˜ν•œ 같은 수λ₯Ό μ—°μ†μœΌλ‘œν•˜λ©΄ μ•ˆλ˜λ―€λ‘œ 2둜 λλ‚˜λŠ” 것은 μ œμ™Έ λœλ‹€.)

dp[5][2] = dp[3][1] + dp[3][3];

// 이것을 μΌλ°˜ν™” ν•˜λ©΄ μ•„λž˜μ™€ κ°™λ‹€.

dp[n][1] = dp[n-2][1] + dp[n-2][3];

3) 3을 λ”ν•˜λŠ” 경우λ₯Ό μ‚΄νŽ΄λ³΄μž
λ§ˆμ§€λ§‰μ— 3을 λ”ν•΄μ£ΌλŠ” κ²½μš°λŠ”,
2λ₯Ό λ§Œλ“œλŠ” μˆ˜μ‹μ—μ„œ 1둜 λλ‚˜λŠ” 것에 3을 λ”ν•˜λŠ”κ²ƒ,
2λ₯Ό λ§Œλ“œλŠ” μˆ˜μ‹μ—μ„œ 2둜 λλ‚˜λŠ” 것에 3을 λ”ν•˜λŠ”κ²ƒμ΄λ‹€.
(이것도 같은 수λ₯Ό μ—°μ†μœΌλ‘œ λ‚˜μ—΄ν• μˆ˜μ—†μœΌλ―€λ‘œ 3으둜 λλ‚˜λŠ” 것은 μ œκ±°ν•œλ‹€.)

dp[5][3] = dp[2][1] + dp[2][2];

// 이것을 μΌλ°˜ν™” ν•˜λ©΄ μ•„λž˜μ™€ κ°™λ‹€.

dp[n][3] = dp[n-3][1] + dp[n-3][2];

μ΄λŸ¬ν•œ 과정을 톡해 결과적으둜 점화식을 λ„μΆœν•΄ λ‚Όμˆ˜μžˆλ‹€.

dp[i][1] = (dp[i-1][2] + dp[i-1][3]) % 1_000_000_009;  
dp[i][2] = (dp[i-2][1] + dp[i-2][3]) % 1_000_000_009;  
dp[i][3] = (dp[i-3][1] + dp[i-3][2]) % 1_000_000_009; (n >= 4)

μ ν™”μ‹μ—μ„œ λͺ¨λ“ˆλŸ¬λ₯Ό μ‚¬μš©ν•˜λŠ” 이유
10μ–΅9둜 λ‚˜λˆ μ„œ 좜λ ₯ν•˜λΌλŠ” μ œν•œ 사항이 μžˆλŠ”λ°, λ§ˆμ§€λ§‰μ— λͺ¨λ“ˆλŸ¬λ₯Ό λ„£κ²Œλ˜λ©΄ 값이 μ •μƒμ μœΌλ‘œ 좜λ ₯λ˜μ§€μ•ŠλŠ”λ‹€. κ·ΈλŸ¬λ―€λ‘œ 계산 κ³Όμ • 쀑간에 λͺ¨λ“ˆλŸ¬λ₯Ό μ‚½μž…ν•œλ‹€.

μ½”λ“œ

import java.util.Scanner;  

public class _123λ”ν•˜κΈ°5 {  

    public static void main(String[] args) {  

        Scanner sc = new Scanner(System.in);  

        int t = sc.nextInt();  

        long[][] dp = new long[100001][4];  

        dp[1][1] = 1; // 1  
        dp[2][2] = 1; // 2  
        dp[3][1] = 1; // 2+1  
        dp[3][2] = 1; // 1+2  
        dp[3][3] = 1; // 3  

        for(int i=4; i<=100000; i++){  
            dp[i][1] = (dp[i-1][2] + dp[i-1][3]) % 1_000_000_009;  
            dp[i][2] = (dp[i-2][1] + dp[i-2][3]) % 1_000_000_009;  
            dp[i][3] = (dp[i-3][1] + dp[i-3][2]) % 1_000_000_009;  
        }  

        for(int i=1; i<=t; i++){  
            int n = sc.nextInt();  
            System.out.println((dp[n][1] + dp[n][2] + dp[n][3]) % 1_000_000_009);  
        }  

        sc.close();  
    }  
}
λ°˜μ‘ν˜•
profile

fee-fi-fo-fum

@hae02y

ν¬μŠ€νŒ…μ΄ μ’‹μ•˜λ‹€λ©΄ "μ’‹μ•„μš”β€οΈ" λ˜λŠ” "κ΅¬λ…πŸ‘πŸ»" ν•΄μ£Όμ„Έμš”!