πŸ‘©β€πŸŽ“κ³΅λΆ€ - 2024.01.31 μ†Œλ§ˆλŒ€λΉ„ λ¬Έμ œν’€μ΄

유령개·2024λ…„ 1μ›” 31일
0

PS-μ•Œκ³ λ¦¬μ¦˜2

λͺ©λ‘ 보기
23/34
post-thumbnail

9184번 - μ‹ λ‚˜λŠ” ν•¨μˆ˜ μ‹€ν–‰

λ¬Έμ œμ— 주어진 μ½”λ“œλ₯Ό μ‹€ν–‰μ‹œν‚€λ €κ³  ν•˜λŠ”λ°
λ¬Έμ œμ—μ„œ ν•΄λ‹Ή μ½”λ“œλ₯Ό μ‹€ν–‰μ‹œν‚€λ©΄ μ‹œκ°„μ΄ λ„ˆλ¬΄ 였래걸릴까봐 κ±±μ •μ΄λžλ‹ˆλ‹€.
ν•΄λ‹Ή μ½”λ“œλ₯Ό μ‹œκ°„μ΄ˆκ³Όκ°€ λ‚˜μ§€ μ•Šκ²Œ μ‹€ν–‰μ‹œν‚€λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄ λ©λ‹ˆλ‹€.

...보자마자 μ§μž‘μ΄ κ°‘λ‹ˆλ‹€. DP의 λ©”λͺ¨μ΄μ œμ΄μ…˜ 기법을 μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.


뢄석

보톡 νŒ©ν† λ¦¬μ–Όκ°™μ€λ°μ„œ λ©”λͺ¨μ΄μ œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©΄ λ³€μˆ˜λ₯Ό ν•˜λ‚˜λ§Œ λ°›μ•„μ„œ memo[ν•΄λ‹Ήλ³€μˆ˜] λΌλŠ” μ”©μœΌλ‘œ κΈ°λ‘ν•˜λŠ”λ° μ΄λ²ˆμ—λŠ” λ³€μˆ˜κ°€ 무렀 μ„Έ κ°œμž…λ‹ˆλ‹€.

보고 λ”± λ– μ˜€λ₯Έ 생각은 3차원 리슀트둜써 memo[a][b][c] 둜 κ΅¬ν˜„ν•˜λŠ”κ²Œ μ •ν•΄κ² κ΅¬λ‚˜ μƒκ°ν–ˆμŠ΅λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ μ €λŠ” 남듀과 같은 길을 κ±·κΈ°λŠ” μ‹«μ–΄ 쑰금 창의적으둜 κ΅¬ν˜„ν•΄λ΄€μŠ΅λ‹ˆλ‹€.

일단 λ©”λͺ¨μ΄μ œμ΄μ…˜μœΌλ‘œμ¨ λ”•μ…”λ„ˆλ¦¬λ₯Ό ν•˜λ‚˜ λ§Œλ“€κ³ , 3개 λ³€μˆ˜λ₯Ό 묢은거

(예λ₯Ό λ“€μ–΄ w(20,20,20) 이라면 dict['202020'] = ν•΄λ‹Ή μž¬κ·€λ¬Έ (w(20,20,20)μ΄λΌλ˜κ°€ w(a,b,c-1) + w(a,b-1,c-1) - w(a,b-1,c) 와 같은 λ“±λ“±...) )

와 같은 ν˜•μ‹μœΌλ‘œ λ”•μ…”λ„ˆλ¦¬λ₯Ό ꡬ성해쀀 ν›„

    if str(a)+str(b)+str(c) in memo.keys():
        return memo[str(a)+str(b)+str(c)]

ν•΄λ‹Ή 값이 key값에 μ‘΄μž¬ν•œλ‹€λ©΄ ν•΄λ‹Ή κ°’μ˜ key에 ν•΄λ‹Ήν•˜λŠ” valueλ₯Ό λ‚΄λ³΄λ‚΄λŠ” μ‹μœΌλ‘œ κ΅¬ν˜„ν•΄λ„ 될 것 κ°™μ•˜μŠ΅λ‹ˆλ‹€.


첫번째 μ‹œλ„

while True:
    a,b,c = map(int,input().split())
    if a==-1 and b==-1 and c==-1:
        break
    print('w(%s, %s, %s) ='%(a,b,c),w(a,b,c))

λ¨Όμ € λ¬Έμ œμ—μ„œ -1,-1,-1이 λ“€μ–΄μ˜€λ©΄ μž…λ ₯을 λ©ˆμΆ”κ³  κ·Έ μ „κΉŒμ§€λŠ” 좜λ ₯ν•˜λΌ ν–ˆμœΌλ―€λ‘œ μœ„μ™€ 같이 좜λ ₯ ν˜•μ‹μ— λ§žμΆ”μ–΄ μ½”λ”©ν•΄μ€λ‹ˆλ‹€.

memo = dict()

def w(a,b,c):

λ‹€μŒμœΌλ‘œ λ©”λͺ¨μ΄μ œμ΄μ…˜μœΌλ‘œμ¨ λ”•μ…”λ„ˆλ¦¬λ₯Ό ν•˜λ‚˜ μ„ μ–Έν•˜κ³  wν•¨μˆ˜ μ œμž‘μ„ μ‹œμž‘ν•©λ‹ˆλ‹€.

    if str(a)+str(b)+str(c) in memo.keys():
        return memo[str(a)+str(b)+str(c)]

μ•„κΉŒ λ§ν•œλŒ€λ‘œ ν˜„μž¬ 탐색쀑인 값이 λ©”λͺ¨μ΄μ œμ΄μ…˜μ˜ 킀값에 있으면 ν•΄λ‹Ή value κ°’μœΌλ‘œ return ν•΄μ€μ‹œλ‹€.

    if a>20 or b>20 or c>20:
        memo[str(a)+str(b)+str(c)] = w(20,20,20)
        return memo[str(a)+str(b)+str(c)]

λ‚˜λ¨Έμ§€λŠ” λ¬Έμ œμ— λ‚˜μ˜¨ μ½”λ“œ κ·ΈλŒ€λ‘œ μž‘μ„±ν•˜λ˜ λ©”λͺ¨μ΄μ œμ΄μ…˜ 기법을 μ‚¬μš©ν•  수 있게 λ©”λͺ¨μ΄μ œμ΄μ…˜μ— λ„£μ–΄ ν•΄λ‹Ή λ©”λͺ¨μ΄μ œμ΄μ…˜ κ°’μœΌλ‘œ return 해주도둝 ν•©μ‹œλ‹€.

    if a>20 or b>20 or c>20:
        memo[str(a)+'empty'+str(b)+'empty'+str(c)] = w(20,20,20)
        return memo[str(a)+'empty'+str(b)+'empty'+str(c)]

    if a<b and b<c:
        memo[str(a)+'empty'+str(b)+'empty'+str(c)] = w(a,b,c-1) + w(a,b-1,c-1) - w(a,b-1,c)
        return memo[str(a)+'empty'+str(b)+'empty'+str(c)]
    else:
        memo[str(a)+'empty'+str(b)+'empty'+str(c)] = w(a-1,b,c) + w(a-1,b-1,c) + w(a-1,b,c-1) - w(a-1,b-1,c-1)
        return memo[str(a)+'empty'+str(b)+'empty'+str(c)]

λ‚˜λ¨Έμ§€λ„ λ™μΌν•œ λ°©μ‹μœΌλ‘œ μž‘μ„±ν•˜λ©΄ λ©λ‹ˆλ‹€.
이제 좜λ ₯ν•΄λ³΄λ‹ˆκΉŒ

값은 μž˜λ‚˜μ˜€λŠ”λ°

μ•Œμˆ˜ μ—†λŠ” 이유둜 ν‹€λ¦½λ‹ˆλ‹€.


μ˜€λ‹΅ 원인 뢄석

곰곰히 μƒκ°ν•΄λ³΄λ‹ˆκΉŒ λ©”λͺ¨μ΄μ œμ΄μ…˜ μž‘μ„±μ„ ν• λ•Œ w(11,11,11)κ³Ό 같은 ν˜•μ‹μ„ κΈ°μž¬λ°›κ²Œ 되면 memo['111111']이 λ˜λŠ”λ°

이게 λ‚˜μ€‘μ— λ©”λͺ¨ μ°Έκ³ λ₯Ό ν• λ•Œ w(1,111,11)이냐, w(1111,1,1)이냐 ꡬ뢄할 방법이 μ—†κΈ° λ•Œλ¬Έμ— λ‚˜λŠ” 였λ₯˜λΌκ³  생각이 λ©λ‹ˆλ‹€.

κ·Έλž˜μ„œ w(a,b,c)사이λ₯Ό ꡬ뢄해쀄 문자λ₯Ό μ•„λ¬΄κ±°λ‚˜ ν•˜λ‚˜ λ„£μ–΄μ£ΌκΈ°λ‘œ ν–ˆμŠ΅λ‹ˆλ‹€.


ν•΄κ²°


memo = dict()

def w(a,b,c):

    if a<=0 or b<=0 or c<=0:
        return 1

    if str(a)+'empty'+str(b)+'empty'+str(c) in memo.keys():
        return memo[str(a)+'empty'+str(b)+'empty'+str(c)]
    
    if a>20 or b>20 or c>20:
        memo[str(a)+'empty'+str(b)+'empty'+str(c)] = w(20,20,20)
        return memo[str(a)+'empty'+str(b)+'empty'+str(c)]

    if a<b and b<c:
        memo[str(a)+'empty'+str(b)+'empty'+str(c)] = w(a,b,c-1) + w(a,b-1,c-1) - w(a,b-1,c)
        return memo[str(a)+'empty'+str(b)+'empty'+str(c)]
    else:
        memo[str(a)+'empty'+str(b)+'empty'+str(c)] = w(a-1,b,c) + w(a-1,b-1,c) + w(a-1,b,c-1) - w(a-1,b-1,c-1)
        return memo[str(a)+'empty'+str(b)+'empty'+str(c)]
    
while True:
    a,b,c = map(int,input().split())
    if a==-1 and b==-1 and c==-1:
        break
    print('w(%s, %s, %s) ='%(a,b,c),w(a,b,c))

λ‹¨μˆœνžˆ a와b사이, 그리고 b와 c사이 λ©”λͺ¨μ΄μ œμ΄μ…˜μ„ μ›ν™œνžˆ 참고될 수 μžˆλ„λ‘ 'empty'λΌλŠ” λ¬Έμžμ—΄μ„ λ„£μ–΄ κ΅¬λΆ„ν•΄μ£ΌκΈ°λ‘œ ν–ˆμŠ΅λ‹ˆλ‹€.



11057번 - 였λ₯΄λ§‰ 수

μœ„μ™€ 같이 μžλ¦¬μˆ˜κ°€ μ£Όμ–΄μ‘Œμ„ λ•Œ ν•΄λ‹Ή μžλ¦¬μˆ˜μ—μ„œ λ‚˜μ˜¬ 수 μžˆλŠ” 였λ₯΄λ§‰ μˆ˜κ°€ λ‚˜μ˜€λŠ” 경우λ₯Ό λͺ¨λ‘ κ΅¬ν•˜λŠ” λ¬Έμ œμž…λ‹ˆλ‹€.


뢄석


일단 μ € μœ„μ— 0,1,2,3,4,5,... λŠ” λ§ˆμ§€λ§‰ μžλ¦Ώμˆ˜μž…λ‹ˆλ‹€.
κ·ΈλŸ¬λ‹ˆκΉŒ 수의 μžλ¦¬μˆ˜κ°€ 1이라면 0으둜 λλ‚˜λŠ” 였λ₯΄λ§‰ μˆ˜λŠ” 1개 (0), 수의 μžλ¦¬μˆ˜κ°€ 2라면 1둜 λλ‚˜λŠ” 였λ₯΄λ§‰ μˆ˜λŠ” 2개(μˆ˜κ°€ 0으둜 μ‹œμž‘ν•  수 μžˆλŒ”μœΌλ‹ˆκ°€ 00,01) 이런 μ”©μž…λ‹ˆλ‹€.

μ΄λ ‡κ²Œ μ­‰ λ‚˜μ—΄ν•΄λ³΄λ©΄ κ·œμΉ™μ„±μ΄ λ³΄μž…λ‹ˆλ‹€.
μœ„μ— ν‘œκΈ°ν•΄λ‘” 3자리수의 2둜 λλ‚˜λŠ” 수(6) = 3자리수의 1둜 λλ‚˜λŠ” 수(3) + 2자리수의 2둜 λλ‚˜λŠ” 수(3)
λΌλŠ” κ·œμΉ™μ„±μ„ μ°Ύμ•„λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

이걸 ν† λŒ€λ‘œ 점화식을 μ„Έμ›Œλ³΄λ©΄

N자리수의 i둜 λλ‚˜λŠ” 수 = N자리수의 i-1둜 λλ‚˜λŠ” 수 + N-1자리수의 i둜 λλ‚˜λŠ” 수

이런 ν˜•μ‹μΌ κ²λ‹ˆλ‹€.

DPλŠλ‚ŒλŒ€λ‘œ 1μžλ¦¬μˆ˜λŠ” 죄닀 초기 κ³ μ •μœΌλ‘œ 박아두고, 2μžλ¦¬μˆ˜λΆ€ν„°λŠ” μœ„ 점화식을 기반으둜 ν’€μ΄ν•˜λ©΄ 될 것 κ°™μŠ΅λ‹ˆλ‹€.


μ½”λ”©

dp = [[0]*10 for _ in range(1001)]
N = int(input())

μžλ¦¬μˆ˜λŠ” 1001κΉŒμ§€ λ‚˜μ˜¬ 수 μžˆλ‹€λ‹ˆκΉŒ 0~9(λλ‚˜λŠ” 수) X 1001 짜리 이차원 리슀트λ₯Ό DPλ°°μ—΄λ‘œμ¨ μ œμž‘ν•΄μ£Όκ² μŠ΅λ‹ˆλ‹€. 그리고 N자리수λ₯Ό λ°›μŠ΅λ‹ˆλ‹€.

for i in range(10):
    dp[1][i] = 1

DPλ₯Ό μ“°κΈ°μœ„ν•œ 초기 계산식 1자리수λ₯Ό μ „λΆ€ 1둜 μ΄ˆκΈ°ν™”ν•΄μ€μ‹œλ‹€.

for i in range(2,N+1):
    for j in range(10):
        dp[i][j] = dp[i-1][j] + dp[i][j-1]

2μžλ¦¬μˆ˜λΆ€ν„°λŠ”, 0~9κΉŒμ§€μ˜ λλ‚˜λŠ” μˆ˜μ— μ•„κΉŒ μ„Έμš΄ 점화식 N자리수의 i둜 λλ‚˜λŠ” 수 = N자리수의 i-1둜 λλ‚˜λŠ” 수 + N-1자리수의 i둜 λλ‚˜λŠ” 수 => dp[i][j] = dp[i-1][j] + dp[i][j-1]
을 λ„£μ–΄μ€μ‹œλ‹€. μ—¬κΈ°μ„œ iλŠ” 자릿수, jλŠ” λλ‚˜λŠ” 수라고 μƒκ°ν•˜μ‹œλ©΄ 될 것 κ°™μŠ΅λ‹ˆλ‹€.

print(sum(dp[N])%10007)

λ§ˆμ§€λ§‰μœΌλ‘œ N에 ν•΄λ‹Ήν•˜λŠ” λ°°μ—΄ (0~9κΉŒμ§€μ˜ λλ‚˜λŠ” 수 기반 였λ₯΄λ§‰ 수의 κ°œμˆ˜λ“€)의 합산을 10007둜 λ‚˜λˆˆ κ°’(문제 쑰건)을 좜λ ₯ν•˜λ©΄ λ©λ‹ˆλ‹€.




profile
ν•œλ¦ΌλŒ€ν•™κ΅ μ •λ³΄κ³Όν•™λŒ€ 2ν•™λ…„ μž¬ν•™μ€‘ / 윑ꡰ μ •λ³΄λ³΄ν˜Έλ³‘ 22-2κΈ°

0개의 λŒ“κΈ€