ABC438 - D - Tail of Snake
ABC438 - D - Tail of Snake
문제
뱀을 N개의 블록으로 나누고, 머리다움, 몸통다움, 꼬리다움을 평가한다. 이 평가 값을 합산할때 가장 큰 값이 나오도록 구역을 나누기로 했다.
길이가 N인 정수수열 A = ( $A_1$ , … , $A_N$ ) , B , C 가 주어질때
\[1 \le x < y < N\]을 만족하는 정수 쌍 (x,y) 에 대해서
\[\sum_{i=1}^{x} A_i + \sum_{i=x+1}^{y} B_i + \sum_{i=y+1}^{N} C_i\]의 최대값은?
제약조건
- $ 3 \le N \le 3 \times 10^5 $
- $ 1 \le A_i , B_i , C_i \le 10^6 $
- 입력되는 모든 값은 정수
bruteforce - 시간초과
N = 300 000 이 최대이다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
N = int(input())
A = list(map(int,input().split()))
B = list(map(int,input().split()))
C = list(map(int,input().split()))
max_v = 0
for x in range(1,N):
for y in range(x+1,N):
s = 0
for i in range(N):
if i<=x:
s += A[i]
elif x < i and i <= y:
s += B[i]
else:
s += C[i]
max_v = max(s,max_v)
print(max_v)
이거는 N^3, 시간초과가 당연함.
dp
한번만 훑으면서 최적의 값을 저장할 수 있다
dp 설계
i번째 블록에 있을 때, 3가지 상태에 있다.
- 상태 0 (머리 중) : 아직 머리 부분을 지나고 있다 (수열 A 선택)
- 상태 1 (몸통 중) : 머리가 끝나고 몸통 부분을 지나고 있다 (수열 B 선택)
- 상태 2 (꼬리 중) : 몸통이 끝나고 꼬리부분 지나는 중 (수열 C 선택)
dp[i][state] 라는 배열을 정의
- dp[i][0] : i번째 블록까지 왔을 떄, 현재 머리 상태인경우 최대 합
- dp[i][1] : 현재 몸통 상태인경우 최대합
- dp[i][2] : 현재 꼬리 상태인 경우 최대합
점화식
- dp[i][0] (현재 머리):
- i-1번 블록도 머리였어야 함
- dp[i][0] = dp[i-1][0] + A[i]
- dp[i][1] (현재 몸통):
- 이전 블록(i-1) 에서 상태는 2가지 case
- 원래 몸통 -> 계속 몸통 (dp[i-1][1])
- 머리 -> 몸통 (dp[i-1][0])
- max(dp[i-1][0], dp[i-1][1]) + B[i]
- 이전 블록(i-1) 에서 상태는 2가지 case
- dp[i][2] (현재 꼬리):
- 이전 블록에서 상태는 2가지 case가 있다
- 꼬리 -> 꼬리 (dp[i-1][2])
- 몸통 -> 꼬리 (dp[i-1][1])
- max(dp[i-1][1], dp[i-1][2]) + C[i]
- 이전 블록에서 상태는 2가지 case가 있다
초기값 설정
불가능한 상태 처리 필요
\[1 \le x < y < N\]- 최소한 1개 블록은 머리여야 하고
- 최소한 1개 몸통
- 최소한 1개 꼬리
따라서
- i=0 은 무조건 머리
- i=1 부터 몸통 등장 가능
- i=2 부터 꼬리 등장 가능
max 함수 비교시 자동 탈락되도록 -inf로 초기화 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
N = int(input())
A = list(map(int,input().split()))
B = list(map(int,input().split()))
C = list(map(int,input().split()))
# init
dp = [[-float('inf') for j in range(3)] for i in range(N)]
dp[0][0] = A[0]
## 나머지를 -inf로 놓으면 알아서 없어지게 됨.
## 가장 오른쪽 위의 값도 자연스럽게 안쓰이게 된다.
# dp
for i in range(1,N):
dp[i][0] = dp[i-1][0] + A[i]
dp[i][1] = max(dp[i-1][0], dp[i-1][1]) + B[i]
dp[i][2] = max(dp[i-1][1], dp[i-1][2]) + C[i]
print(dp[-1][-1])
dp[i][state] 이거 떠올릴수 있으면 어떻게든 풀었을것 같은데, 여기까지 왔을때 시간이 없기도 했고 …
아직 이런 문제를 잘 못하는것 보면 좀 답답하기도 하고… 어쨌든 1년만에 atcoder를 했다
This post is licensed under CC BY 4.0 by the author.