AtCoder DP Contest
Β - Last update: 2023-11-01

AtCoder Educational DP Contest

μ•„μ£Ό ꡐ윑적인 DP 문제 λͺ¨μŒμ§‘이닀. μ—¬κΈ°μ„œλŠ” κ°„λž΅ν•˜κ²Œ 풀이λ₯Ό 정리해본닀.

A, B - Frog 1, 2

DP[i]DP[i]κ°€ μ΅œμ†Œ λΉ„μš©μ„ λ“€κ³  μžˆκ²Œλ” ν•˜λ©΄ λ˜λŠ” μœ ν˜•. 계단 였λ₯΄λŠ” λ¬Έμ œλž‘λ„ λΉ„μŠ·ν•˜λ‹€. B번의 κ²½μš°μ—λŠ” μ΅œλŒ€ K≀100K \le 100 κΉŒμ§€ 이동 κ°€λŠ₯ν•˜λ‹€λŠ” 쑰건이 μžˆλ‹€. Bλ²ˆμ—μ„œ λ‹¬λΌμ§€λŠ” 것은 iiκ°€ 증가할 λ•Œλ§ˆλ‹€ μ΅œλŒ€ KK 이전 indexκΉŒμ§€ ν™•μΈν•΄μ„œ λ“€κ³ μ˜€λ©΄ λœλ‹€λŠ” 점.

C - Vacation

μ΄λ²ˆμ—λŠ” λ§ˆμ§€λ§‰ μƒνƒœλ₯Ό 같이 μ €μž₯ν•˜κ³  μžˆμ„ ν•„μš”κ°€ μžˆλ‹€. μ™œλƒλ©΄, 같은 ν™œλ™μ„ 2일 연속 ν•˜μ§€ λͺ»ν•˜κΈ° λ•Œλ¬Έμ—, ii 번째 λ‚ μ˜ ν™œλ™μ„ ν•˜λ©΄μ„œ 얻은 max 행볡도와 λ”λΆˆμ–΄, 그것을 λ‹¬μ„±ν–ˆμ„ λ•Œ μ–΄λ–€ ν™œλ™μ„ ν–ˆμ—ˆλŠ”μ§€κ°€ μ €μž₯이 λ˜μ–΄μ•Ό ν•˜λŠ” 것. 이런 μœ ν˜•μ—μ„œλŠ” 보톡 DP의 차원을 λŠ˜λ €μ„œ ν•΄κ²°ν•˜κ³€ ν•œλ‹€. DP[k][i]DP[k][i]λ₯Ό μ„ μ–Έν•˜μ—¬, 각 값이 iλ²ˆμ§Έλ‚ μ—μ„œμ˜ max 행볡도λ₯Ό μ €μž₯ν•˜λ˜ κ·Έ λ§ˆμ§€λ§‰ ν™œλ™μ΄ k인 경우라고 μƒκ°ν•˜λ©΄ λœλ‹€.

D, E - Knapsack 1, 2

이름뢀터 λŒ€λ†“κ³  μœ ν˜•μ„ μ•”μ‹œν•œλ‹€. 일반적으둜 Knapsack μœ ν˜•μ€ 무게의 μƒν•œμ΄ W≀106W \le 10^6 μ •λ„λ‘œ μ£Όκ³  κ·Έ 무게 κΈ°μ€€μœΌλ‘œ 생각할 수 μžˆκ²Œλ” ν•΄μ„œ ν’€λ¦¬λŠ”λ°, Dλ²ˆμ€ μ™„μ „ κ·Έ μœ ν˜•μ΄κ³ , Eλ²ˆμ€ ν•œλ²ˆ κΌ¬μ•˜λ‹€.

E번의 κ²½μš°μ—λŠ” W≀109W \le 10^9 이기 λ•Œλ¬Έμ—, 였히렀 V≀103V \le 10^3은 점을 μ΄μš©ν•˜λ©΄ λœλ‹€. λ¬Έμ œμ—μ„œ N≀100N \le 100 이기 λ•Œλ¬Έμ—, μ΅œλŒ€ ν–‰λ³΅λ„μ˜ μ œν•œμ€ V≀105V \le 10^5κ°€ 되고, ν•΄λ‹Ή VVμ—μ„œμ˜ μ΅œμ†Œ WWλ₯Ό μ €μž₯ν•΄λ‘” ν›„, λ‚˜μ€‘μ— max VVλ₯Ό λ³΄λ©΄μ„œ WWκ°€ μœ νš¨ν•œμ§€(μ΅œλŒ€ μ œν•œμ— μ•ˆν„°μ‘ŒλŠ”μ§€) ν™•μΈν•˜λ©΄ λœλ‹€. μ•„λž˜ BOJ λ¬Έμ œμ—μ„œ 많이 λ‹Ήν–ˆμ—ˆλ‹€.

F - LCS

μ—­μ‹œ λŒ€ν‘œ μœ ν˜•. κ΄€λ ¨ν•΄μ„œλŠ” μ•„λž˜μ— μ •λ¦¬ν•΄λ‘μ—ˆλ‹€.

G - Longest Path

Tree DP μœ ν˜•ν•˜κ³  μœ μ‚¬ν•œ 문제. ν’€μ΄λŠ” μ—¬λŸ¬ 방법이 μ‘΄μž¬ν•˜λŠ” 것 κ°™μ§€λ§Œ 일단 일반적인 Tree 처럼 ν’€ μˆ˜λŠ” μ—†λ‹€. (λ°©ν–₯이 μžˆλŠ” κ·Έλž˜ν”„)

indegreeκ°€ 0인 정점듀을 좜발점으둜 작고 μ‹œμž‘ν•œ λ‹€μŒ, leaf에 λ„λ‹¬ν–ˆμ„ κ²½μš°λΆ€ν„° μ‹œμž‘ν•΄μ„œ depthλ₯Ό μ±„μ›Œμ£ΌλŠ” λ°©μ‹μœΌλ‘œ ν•˜λ©΄, 쀑볡방문을 ν”Όν•˜λ©΄μ„œ λͺ¨λ“  μ •μ μ˜ depthλ₯Ό μ±„μšΈ 수 μžˆλ‹€. 이듀 쀑 max 값을 κ΅¬ν•˜λ©΄ κ·Έλž˜ν”„μ—μ„œμ˜ κ°€μž₯ κΈ΄ 경둜의 거리가 λœλ‹€.

πŸ‘‰ 펼치기
struct Node {
int depth;
int inCnt;
vector<int> edges;
} n[100010];
int dfs(int i) {
if (n[i].edges.size() == 0) {
// leaf
return 0;
}
if (n[i].depth != 0) return n[i].depth;
for(auto& t: n[i].edges) {
int res = dfs(t);
n[i].depth = max(n[i].depth, res + 1);
}
return n[i].depth;
}
void solve() {
int ans = 0;
for(int i = 1; i <= N; ++i) {
if (n[i].inCnt == 0) {
ans = max(ans, dfs(i));
}
}
printf("%d", ans);
}

H - Grid 1

빈좜 μœ ν˜•. Gridμ—μ„œμ˜ 이동 λ°©ν–₯은 μ•„λž« λ°©ν–₯κ³Ό 우츑 뿐이기 λ•Œλ¬Έμ—, μ—­μœΌλ‘œ 경우의 μˆ˜λŠ” μœ„μͺ½κ³Ό μ™Όμͺ½μ—μ„œ μ˜€λŠ” κ²ƒμ˜ ν•©μœΌλ‘œ ꡬ해주면 λœλ‹€. λ‹€λ§Œ, ν˜„μž¬ μœ„μΉ˜κ°€ 벽일 경우 κ·Έ 값을 0으둜 μ΄ˆκΈ°ν™”ν•˜λŠ” 것은 μžŠμ–΄μ„œλŠ” μ•ˆλœλ‹€.

I - Coins

ν”νžˆ ν™•λ₯  DP라고 λΆˆλ¦¬λŠ” μœ ν˜•μΈ λ“― ν•˜λ‹€. λ‹¨κ³„λ³„λ‘œ μƒκ°ν•΄λ³΄μž.

  1. μ•žλ©΄μ΄ 0개인 경우의 ν™•λ₯ 
    • (1βˆ’p1)(1βˆ’p2)(1βˆ’p3)...(1βˆ’pN)(1 - p_1)(1 - p_2)(1 - p_3)...(1 - p_N)
  2. μ•žλ©΄μ΄ 1개인 경우의 ν™•λ₯ 
    • p1(1βˆ’p2)(1βˆ’p3)...(1βˆ’pN)+(1βˆ’p1)p2(1βˆ’p3)...(1βˆ’pN)+...+(1βˆ’p1)(1βˆ’p2)(1βˆ’p3)...(1βˆ’pNβˆ’1)pNp_1(1 - p_2)(1 - p_3)...(1 - p_N) + (1 - p_1)p_2(1 - p_3)...(1 - p_N) + ... + (1 - p_1)(1 - p_2)(1 - p_3)...(1 - p_{N-1})p_N
  3. μ•žλ©΄μ΄ N개인 경우의 ν™•λ₯ 
    • p1p2p3...pNp_1p_2p_3...p_N

그런데, 이것을 ν•œλ²ˆμ— λ‹€ κ³„μ‚°ν•˜κΈ°μ—” μ—°μ‚°λŸ‰μ΄ λ„ˆλ¬΄ λ§Žλ‹€. 이λ₯Ό 쀄이기 μœ„ν•΄ DP의 μ£Όμš” 풀이법 쀑 ν•˜λ‚˜μΈ μž‘μ€ κ²½μš°λΆ€ν„° μ‹œμž‘ν•΄λ³΄λŠ” 기법을 μ μš©ν•΄λ³Ό 수 μžˆλ‹€. DP[i][j]DP[i][j]λ₯Ό ii번째 λ™μ „κΉŒμ§€λ₯Ό κ³ λ €ν–ˆμ„ λ•Œ jjκ°œκ°€ μ•žλ©΄μΈ ν™•λ₯ λ‘œ μ •μ˜ν•˜μž. 그러면 μ •μ˜μ— μ˜ν•΄, DP[1][0]=1βˆ’p1DP[1][0] = 1 - p_1, DP[1][1]=p1DP[1][1] = p_1 이 λœλ‹€. 이 μƒνƒœλ‘œλΆ€ν„° μ‹œμž‘ν•˜λ©΄, μƒνƒœ 전이λ₯Ό μ‹œν‚¬ 수 μžˆλ‹€. iiκ°€ μž‘μ€ κ²½μš°λΆ€ν„° ν•œλ²ˆ λ”°λΌκ°€λ³΄μž.

  1. i = 2인 경우
    • DP[2][0]=DP[1][0]Γ—(1βˆ’p2)DP[2][0] = DP[1][0] \times (1 - p_2)
    • DP[2][1]=DP[1][0]Γ—p2+DP[1][1]Γ—(1βˆ’p2)DP[2][1] = DP[1][0] \times p_2 + DP[1][1] \times (1 - p_2)
    • DP[2][2]=DP[1][1]Γ—p2DP[2][2] = DP[1][1] \times p_2
  2. i = 3인 경우
    • DP[3][0]=DP[2][0]Γ—(1βˆ’p3)DP[3][0] = DP[2][0] \times (1 - p_3)
    • DP[3][1]=DP[2][0]Γ—p3+DP[2][1]Γ—(1βˆ’p3)DP[3][1] = DP[2][0] \times p_3 + DP[2][1] \times (1 - p_3)
    • DP[3][2]=DP[2][1]Γ—p3+DP[2][2]Γ—(1βˆ’p3)DP[3][2] = DP[2][1] \times p_3 + DP[2][2] \times (1 - p_3)
    • DP[3][3]=DP[2][2]Γ—p3DP[3][3] = DP[2][2] \times p_3

μ—¬κΈ°κΉŒμ§€ 보면 κ·œμΉ™μ΄ 보인닀. μ „λΆ€ λ‹€ μ•žλ©΄μΈ κ²½μš°μ™€ μ „λΆ€ λ‹€ 뒷면인 경우λ₯Ό μ œμ™Έν•˜λ©΄, ν™•λ₯  μƒνƒœμ „μ΄κ°€ jj와 jβˆ’1j-1 두 κ³³μ—μ„œ 올 수 μžˆλ‹€. 이λ₯Ό 톡해 κ΅¬ν˜„ν•  수 μžˆλ‹€.

πŸ‘‰ 펼치기
// 초기쑰건
DP[1][0] = 1.0 - p[1];
DP[1][1] = p[1];
for(int i = 2; i <= N; ++i) {
for(int j = 0; j <= i; ++j) {
if (j == 0) {
DP[i][0] = DP[i - 1][0] * (1 - p[i]);
} else if (j < i) {
DP[i][j] = DP[i - 1][j] * (1 - p[i]) + DP[i - 1][j - 1] * p[i];
} else {
DP[i][j] = DP[i - 1][j - 1] * p[i];
}
}
}

μ΅œμ’…μ μœΌλ‘œ κ΅¬ν•˜κ³ μž ν•˜λŠ” 것은 μ•žλ©΄μ΄ 뒷면보닀 많이 λ‚˜μ™”μ„ λ•ŒμΈλ°, 이것은 DP[N][N/2+1]DP[N][N/2+1] ~ DP[N][N]DP[N][N] 의 합을 κ΅¬ν•˜λ©΄ κ³„μ‚°λœλ‹€.

J - Sushi

κΈ°λŒ“κ°’ DP. Jλ²ˆμ€ 풀이에 μ‹€νŒ¨ν–ˆλ‹€. 핡심은 DP[i][j][k]DP[i][j][k]λ₯Ό νŠΉμ • μƒνƒœμ—μ„œμ˜ κΈ°λŒ“κ°’μœΌλ‘œ μ •μ˜ν•˜λŠ”λ°, ii, jj, kkλŠ” 각각 초λ°₯이 1개, 2개, 3개 남은 μ ‘μ‹œμ˜ 수둜 μ •μ˜ν•΄μ„œ μƒνƒœκ³΅κ°„μ„ μ€„μ΄λŠ” 것이 μ•„μ΄λ””μ–΄μ˜ 핡심이닀.

Iλ²ˆμ—μ„œλŠ” ii개의 동전을 κ³ λ €ν•œ μƒνƒœμ—μ„œ i+1i+1개의 동전을 κ³ λ €ν•œ μƒν™©μœΌλ‘œ 전이λ₯Ό ν–ˆμ—ˆλ‹€. 이와 μœ μ‚¬ν•˜κ²Œ ν•  수 μžˆλ‹€. N=4,i=1,j=1,k=1N=4, i=1, j=1, k=1 인 상황을 κ°€μ •ν•΄λ³΄μž.

  1. ν•΄λ‹Ήν•˜λŠ” 상황은 DP[1][1][1]DP[1][1][1]둜 λ³Ό 수 μžˆλ‹€.
  2. p=14p = \frac 1 4둜 이미 아무것도 μ—†λŠ” μ ‘μ‹œλ₯Ό κ³ λ₯Έλ‹€. μƒνƒœκ°€ 자기 μžμ‹ μœΌλ‘œ μ „μ΄λœλ‹€.
  3. p=14p = \frac 1 4둜 초λ°₯이 1개 μžˆλŠ” μ ‘μ‹œλ₯Ό κ³ λ₯Έλ‹€. μƒνƒœκ°€ DP[0][1][1]DP[0][1][1]둜 μ „μ΄λœλ‹€.
  4. p=14p = \frac 1 4둜 초λ°₯이 2개 μžˆλŠ” μ ‘μ‹œλ₯Ό κ³ λ₯Έλ‹€. μƒνƒœκ°€ DP[2][0][1]DP[2][0][1]둜 μ „μ΄λœλ‹€.
  5. p=14p = \frac 1 4둜 초λ°₯이 3개 μžˆλŠ” μ ‘μ‹œλ₯Ό κ³ λ₯Έλ‹€. μƒνƒœκ°€ DP[1][2][0]DP[1][2][0]둜 μ „μ΄λœλ‹€.

그런데 μœ„μ²˜λŸΌ μƒκ°ν•˜λ‹€λ³΄λ‹ˆ λ¬Έμ œκ°€ ν•˜λ‚˜ μžˆλ‹€. λ°”λ‘œ 1번 상황인데, 이 경우 자기 μžμ‹ μ„ μ°Έμ‘°ν•˜λŠ” 상황이 λœλ‹€. κ·Έλ ‡μ§€λ§Œ, μœ„ 링크에 μ •λ¦¬ν•œ 이둠처럼, μ „μ΄λ˜μ–΄ μ˜€λŠ” ν™•λ₯ λ“€μ„ κ³±ν•΄μ„œ κ³„μ‚°ν•˜κ²Œ λ˜λ―€λ‘œ μˆ˜μ‹μ„ μ „κ°œν•˜λŠ”λ°μ— λ¬Έμ œλŠ” μ—†λ‹€. μœ„ 4κ°€μ§€ caseλ₯Ό ν•œλ²ˆμ— μ •λ¦¬ν•˜λ©΄ μ•„λž˜μ™€ 같이 λœλ‹€.

  • DP[1][1][1]=14(DP[1][1][1]+DP[0][1][1]+DP[2][0][1]+DP[1][2][0])+1DP[1][1][1] = \frac 1 4 (DP[1][1][1] + DP[0][1][1] + DP[2][0][1] + DP[1][2][0]) + 1

이 μˆ˜μ‹μ„ μ „κ°œν•΄μ„œ ν’€λ©΄ λœλ‹€. 결ꡭ은 이 μΌ€μ΄μŠ€λ₯Ό ν™•μž₯ν•΄μ„œ μΌλ°˜ν™”ν•œ μˆ˜μ‹μœΌλ‘œ κ³„μ‚°ν•˜λ©΄ λ¬Έμ œκ°€ ν’€λ¦°λ‹€.

  • DP[i][j][k]=Nβˆ’iβˆ’jβˆ’kNDP[i][j][k]+iNDP[iβˆ’1][j][k]+jNDP[i+1][jβˆ’1][k]+kNDP[i][j+1][kβˆ’1]+1DP[i][j][k] = \frac {N - i - j - k} N DP[i][j][k] \newline \quad\quad\quad\quad\quad\quad + \frac i N DP[i - 1][j][k] \newline \quad\quad\quad\quad\quad\quad + \frac j N DP[i + 1][j - 1][k] \newline \quad\quad\quad\quad\quad\quad + \frac k N DP[i][j + 1][k - 1] \newline \quad\quad\quad\quad\quad\quad + 1

K - Stones

풀이 μ‹€νŒ¨ 2. μƒλ‹Ήνžˆ μ•Œλ €μ§„ 문제 μœ ν˜•μ΄μ§€λ§Œ, 이 문제λ₯Ό μ ‘ν•˜κΈ° μ „κΉŒμ§€ κ²Œμž„μ΄λ‘  μžμ²΄μ— λŒ€ν•΄μ„œ 정리λ₯Ό μ•„μ˜ˆ ν•˜μ§€ μ•Šμ•˜μ—ˆλ‹€. μœ„ 에디토리얼 글이 μƒλ‹Ήνžˆ 잘 λ˜μ–΄ μžˆμ–΄μ„œ, ν•΄λ‹Ή 글을 λ°”νƒ•μœΌλ‘œ 정리λ₯Ό μ’€ 해보렀고 ν•œλ‹€.

문제λ₯Ό λ‹¨μˆœν™”ν•΄μ„œ, K개의 λŒλ¬΄λ€μ—μ„œ 2λͺ…μ˜ ν”Œλ ˆμ΄μ–΄κ°€ 1개, 2개, 3개 λ‹¨μœ„λ‘œλ§Œ λŒμ„ λΉΌλ‚Ό 수 μžˆλ‹€κ³  κ°€μ •ν•˜κ³  문제λ₯Ό μƒκ°ν•΄λ³΄μž. (문제 쑰건과 λ™μΌν•˜κ²Œ 더 이상 λŒλ¬΄λ€μ—μ„œ λŒμ„ κ°€μ Έκ°€μ§€ λͺ»ν•˜λŠ” ν”Œλ ˆμ΄μ–΄μ˜ νŒ¨λ°°μ΄λ‹€) 이 문제의 해법은 마치 λ² μŠ€ν‚¨λΌλΉˆμŠ€ 31 κ²Œμž„κ³Ό μœ μ‚¬ν•œλ°, μ•„λž˜μ™€ κ°™μŒμ΄ μ•Œλ €μ Έ μžˆλ‹€.

  • Kκ°€ 4의 배수라면, ν›„μˆ˜ ν•„μŠΉ
  • Kκ°€ 4의 λ°°μˆ˜κ°€ μ•„λ‹ˆλΌλ©΄, μ„ μˆ˜ ν•„μŠΉ

κ²Œμž„κ³Όμ •μ„ 생각해보면, 각 μƒνƒœμ—μ„œ 선곡이든 후곡이든 남은 돌의 수λ₯Ό 4의 배수둜 λ§žμΆ”κ²Œ 되면, μƒλŒ€κ°€ λŒμ„ λͺ‡κ°œλ₯Ό κ°€μ Έκ°€λ“  μŠΉλ¦¬ν•  수 μžˆμŒμ„ μ•Œ 수 μžˆλ‹€. λ§ˆμ§€λ§‰ 상황을 μƒκ°ν•œ λ‹€μŒ 사고λ₯Ό ν™•μž₯ν•˜λ©΄ λœλ‹€.

  • K=0K = 0, ν˜„μž¬ ν„΄μ˜ ν”Œλ ˆμ΄μ–΄μ˜ νŒ¨λ°°μ΄λ‹€. (κ°€μ Έκ°ˆκ²Œ μ—†μŒ)
  • K≀3K \le 3, ν˜„μž¬ ν„΄μ˜ ν”Œλ ˆμ΄μ–΄μ˜ 승리! λ‹€ κ°€μ Έκ°€λ©΄ λœλ‹€.
  • K=4K = 4, ν˜„μž¬ ν„΄μ˜ ν”Œλ ˆμ΄μ–΄μ˜ νŒ¨λ°°μ΄λ‹€. μ–΄λ–»κ²Œ 가져가도 νŒ¨λ°°ν•˜κ²Œ λœλ‹€.
  • K=5K = 5, ν˜„μž¬ ν„΄μ˜ ν”Œλ ˆμ΄μ–΄μ˜ 승리! 4κ°€ νŒ¨λ°°ν•˜λŠ” flagμ΄λ―€λ‘œ, 1개만 κ°€μ Έκ°€λ©΄ λœλ‹€.
  • K=6,7K = 6, 7, ν˜„μž¬ ν„΄μ˜ ν”Œλ ˆμ΄μ–΄μ˜ 승리! 5일 λ•Œμ˜ μ „λž΅κ³Ό λ§ˆμ°¬κ°€μ§€λ‘œ ν•˜λ©΄ λœλ‹€.
  • K=8K = 8, ν˜„μž¬ ν„΄μ˜ ν”Œλ ˆμ΄μ–΄μ˜ νŒ¨λ°°μ΄λ‹€. K=4K = 4와 μœ μ‚¬ν•˜κ²Œ, μ–΄λ–»κ²Œ 가져가더라도 K=4K = 4둜 μ „μ΄λ˜κ²Œ λ˜μ–΄ νŒ¨λ°°ν•˜κ²Œ λœλ‹€.

이 μ—­μ‹œ μΌμ’…μ˜ DP둜, DP[0]DP[0] λΆ€ν„° μ‹œμž‘ν•΄μ„œ μ „μ΄μ‹œν‚€λ©΄μ„œ ꡬ할 수 μžˆλ‹€.

... How?

🏷️ 주제 λͺ©λ‘: