PS

백준 9465. 스티커

tose33 2021. 3. 2. 17:16

다시 푼 문제.

www.acmicpc.net/problem/9465

 

9465번: 스티커

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 n (1 ≤ n ≤ 100,000)이 주어진다. 다음 두 줄에는 n개의 정수가 주어지며, 각 정수는 그 위치에 해당하는 스티커의

www.acmicpc.net

이전 글 : tose33.tistory.com/17

 

d[n] : 2 x n 의 스티커에서 점수의 합이 최대가 되는 점수.

 

그런데 스티커를 때어내면 위,아래,좌,우 의 스티커는 못쓰게된다. 

따라서 n번째 스티커를 때어낼때 케이스를 나눠 생각한다.

 

d[n][0] : n번째에 스티커를 안때어냄

d[n][1] : n번쨰에서 위쪽의 스티커를 때어냄.

d[n][2] : n번째에서 아랫쪽의 스티커를 때어냄.

 

 

1. d[n][0] : n번째에 스티커를 안때어냄

이 경우 이전 n-1번째에서 아래 스티커를 때든, 위 스티커를 때든, 스티커를 안때든 상관이없다. 따라서

d[n][0] = max(d[n-1][0], d[n-1][1], d[n-1][2])

 

2. d[n][1] : n번쨰에서 위쪽의 스티커를 때어냄.

이 경우 n번째에서 위쪽의 스티커를 때어내려면, n-1번째에서 스티커를 안때거나, 아랫쪽의 스티커를 때어냈어야 한다. 따라서

n-1번째에서 아랫쪽을 때어냈을때의 최대점수 d[n-1][2] 와 n-1번째 에서 안때어냈을 때의 최대 점수 d[n-1][0]중 큰 값에

n번째 에서 위의 점수인 score[0][n]을 더한값이다.

d[n][1] = max(d[n-1][0], d[n-1][2]) + score[0][n]

 

3. d[n][2] : n번째에서 아랫쪽의 스티커를 때어냄.

이 경우 n번째에서 아랫쪽의 스티커를 때어내려면, n-1번째에서 스티커를 안때거나, 위쪽의 스티커를 때어냈어야 한다. 따라서

n-1번째에서 위쪽응ㄹ 때어냈을때의 최대점수인 d[n-1][1]과 n-1번째에서 안때어냈을 떄의 최대점수 d[n-1][0]중 큰 값에, 

n번째 에서 아래의 점수인 score[1][n]을 더한값이다.

d[n][2] = max(d[n-1][0], d[n-1][1]) + score[1][n] 

 

이렇게 bottom-up으로 데이터를 n번째 까지 쌓아간다. 

그리고 d[n][0], d[n][1], d[n][2] 중 가장 큰 값이 정답이다. 

 

#include <iostream>
using namespace std;
#include <algorithm>

int d[100001][3];
int score[2][100001];

int main() {
    int t;
    cin >> t;
    while(t--) {
        int n;
        cin >> n;

        for(int i = 0; i < 2; i++) {
            for(int j = 1; j <= n; j++) {
                cin >> score[i][j];
            }
        }

        d[1][0] = 0; // 안떄어냄
        d[1][1] = score[0][1]; // 위를 때어냄
        d[1][2] = score[1][1]; // 아래를 때어냄

        for(int i = 2; i <= n; i++) {
            d[i][0] = max({d[i-1][0], d[i-1][1], d[i-1][2]});
            d[i][1] = max(d[i-1][2], d[i-1][0]) + score[0][i];
            d[i][2] = max(d[i-1][1], d[i-1][0]) + score[1][i];
        }

        cout << max({d[n][0], d[n][1], d[n][2]}) << '\n';

    }
}