포스트

BOJ 27163 벚꽃 내리는 시대에 결투를

sorohue가 PS하는 블로그

BOJ 27163 벚꽃 내리는 시대에 결투를

문제 링크입니다.

살아남을 수 있는지 판단하기

살아남기 위해서는 마지막 공격을 받은 뒤 라이프가 1 이상이여야 합니다. 오라는 내 생존 여부를 직접적으로 결정하진 않지만, 남은 라이프가 같다면 오라가 많은 쪽이 공격을 흘릴 가능성이 더 높습니다.

여기서 다음과 같은 식을 세워 봅시다.

  • $D[i][j]$ : $i$번째 공격을 받은 후 라이프가 $j$ 이상인 채로 남길 수 있는 최대 오라

이 DP는 공격이 들어옴에 따라 배낭 문제처럼 DP 테이블을 채워 주면 쉽게 구할 수 있습니다. Bottom-Up으로 구하는 쪽이 편할 겁니다.

도달 불가능한 상태의 표현을 위해 기본적으로 테이블은 -1과 같이 절대 나오지 않을 값으로 초기화해 줍니다. 이때, 만약 N번째 공격을 받은 뒤 살아남을 수 있다면, $D[N][1]$은 0 이상이 됩니다.

살아남는 방법 찾기

이 DP를 역추적해서 안 아프게 맞는 방법을 찾아봅시다.

추가로 다음과 같은 값을 관리합니다.

  • $V[i][j]$ : $D[i][j]$의 값을 최대화하기 위해 i번째 공격을 맞는 방법 (0이면 라이프, 1이면 오라)

DP를 돌릴 때 V의 값도 함께 갱신해 주면, 역추적은 $D[N][1]$부터 $V$의 값에 따라 라이프 또는 오라를 회복시키면서 돌아가는 컨셉으로 해결할 수 있습니다.

최종 시간 복잡도 $\mathcal{O}(NL)$에 문제를 해결할 수 있습니다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include<bits/stdc++.h>
using namespace std;

int d[5432][5432];
bool v[5432][5432];
int n, a, l;
int ld[5432];

int main(){
	cin.tie(0);cout.tie(0);ios::sync_with_stdio(false);
	memset(d, -1, sizeof(d));
	cin >> n >> a >> l;
	for(int i = 1; i <= l; i++) d[0][i] = a;
	
	for(int i = 1; i <= n; i++){
		int adam, ldam; cin >> adam >> ldam;
		ld[i] = ldam;
		
		if(adam == -1){
			for(int j = l; j > ldam; j--){
				if(d[i-1][j] != -1){
					d[i][j-ldam] = d[i-1][j];
					v[i][j-ldam] = 1;
				}
			}
		}
		
		else if(ldam == -1){
			for(int j = l; j >= 1; j--){
				if(d[i-1][j] != -1){
					d[i][j] = max(0, d[i-1][j]-adam);
					v[i][j] = 0;
				}
			}
		}
		
		else{
			for(int j = 1; j <= l; j++){
				if(d[i-1][j] >= adam){
					d[i][j] = d[i-1][j]-adam;
					v[i][j] = 0;
				}
				if(j > ldam){
					if(d[i][j-ldam] < d[i-1][j]){
						d[i][j-ldam] = d[i-1][j];
						v[i][j-ldam] = 1;
					}
				}
			}
		}
	}
	if(d[n][1] != -1){
		cout << "YES\n";
		int life = 1;
		stack<char> st;
		for(int i = n; i >= 1; i--){
			if(v[i][life]){
				st.push('L');
				life += ld[i];
			}
			else{
				st.push('A');
			}
		}
		while(!st.empty()){
			cout << st.top();
			st.pop();
		}
	}
	else cout << "NO";
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.