백준 1462 - 퀴즈쇼

Updated:

Categories:

Tags: ,

BOJ 1462 - 퀴즈쇼

풀이

dp[i][0] := 1~i 까지 문제를 푸는데, i를 풀고 나서 남은 코인의 갯수가 0개일 때의 최댓값
dp[i][1] := 1~i 가지 문제를 푸는데, i를 풀고 나서 남은 코인의 갯수와 상관없이 최댓값

위 처럼 2가지 dp를 저장한다고 하자.

먼저 dp[i][0]를 생각해보자.

  1. i번 문제를 맞춰서 보너스 코인을 받아 코인을 모두 소모함.
    dp[i-m][0] + (scoreAcc[i] - scoreAcc[i-m]) + bonus[i]
    1. i-m까지 문제를 풀고 나서 코인이 0개가 되었을 때의 최댓값 := dp[i-m][0]
    2. i-m+1 ~ i 까지의 문제를 모두 맞추고 i번 째 문제에서 보너스 점수를 받음 := (scoreAcc[i] - scoreAcc[i-m]) + bonus[i]
  2. i번 문제를 틀려서 모든 코인을 잃음.
    dp[i-1][1] - score[i]
    i-1까지 최댓값에 i번째 문제를 틀려서 점수를 빼준다. 위와 같이 2가지 케이스가 된다.

그럼 이번에는 dp[i][1]을 생각해보자.

  1. i번 맞추기
    1. i번을 맞춤으로써, M개 채움
    2. i번을 맞춰도 M개를 채우지 못 함.
  2. i번 틀리기 위와 같이 총 3개의 케이스가 있다.
    그러나 우리는 dp[i][0]에서 이미 1-1번과 2번을 모두 계산했음을 알 수 있다.
    그렇다면 우리는 1-2번만 해결하면 되고, 이는 dp[i-1][1] + score[i]이다.

여기서 의문의 생기는데 dp[i-1][1] + score[i]에서 i-1까지의 최댓값 상황에서 코인이 몇 개인지 알아야 i번째에 보너스를 더할지 안 더할지를 할 수 있지 않을까라는 의문이 생길 수 있다.
그러나, 만약 i번째에서 M개를 채웠다면 이는 결국 1-1이다. 그리고 점수들은 모두 음이 아닌 정수이므로 무조건 1-1의 경우가 저장된 dp[i][0]가 클 것이고 결국 max함수로 비교하면 이를 덮어씌울 것이다. 따라서 우리는 dp[i-1][1]이 몇 개의 코인을 모았는지 신경쓸 필요가 없다.

코드

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
72
73
74
75
76
#include <bits/stdc++.h>

#define endl "\n"
#define all(v) (v).begin(), (v).end()
#define For(i, a, b) for(int i=(a); i<(b); i++)
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define Bor(i, a, b) for(int i=(a)-1; i>=(b); i--)
#define BOR(i, a, b) for(int i=(a); i>=(b); i--)
#define ft first
#define sd second

using namespace std;
using ll = long long;
using lll = __int128_t;
using ulll = __uint128_t;
using ull = unsigned long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using ti3 = tuple<int, int, int>;
using tl3 = tuple<ll, ll, ll>;

template<typename T> using ve = vector<T>;
template<typename T> using vve = vector<vector<T>>;

template<class T> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
template<class T> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }

const int INF = 987654321;
const int INF0 = numeric_limits<int>::max();
const ll LNF = 987654321987654321;
const ll LNF0 = numeric_limits<ll>::max();

int n, m;
ve<ll> score, bonus, scoreAcc;
vve<ll> dp;

void solve() {
    cin >> n >> m;
    score = ve<ll>(n+1,0);
    bonus = ve<ll>(n+1,0);
    scoreAcc = ve<ll>(n+1,0);
    dp = vve<ll>(n+1, ve<ll>(2, -INF0));

    FOR(i,1,n) {
        cin >> score[i];
        scoreAcc[i] = score[i] + scoreAcc[i-1];
    }
    FOR(i,1,n) cin >> bonus[i];

    dp[0][0] = dp[0][1] = 0;
    FOR(i,1,n) {
        ckmax(dp[i][0], dp[i-1][1] - score[i]);
        if(i-m>=0) ckmax(dp[i][0], scoreAcc[i]-scoreAcc[i-m] + bonus[i] + dp[i-m][0]);

        ckmax(dp[i][1], dp[i][0]);
        ckmax(dp[i][1], dp[i-1][1] + score[i]);
    }
    cout << dp[n][1] << endl;
}

int main(void) {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int TC=1;
//    cin >> TC;
    FOR(tc, 1, TC) {
//        cout << "Case #" << tc << ": ";
        solve();
    }


    return 0;
}

Leave a comment