백준 1462 - 퀴즈쇼
Updated:
Categories: Problem Solving
Tags: 누적합, 다이나믹-프로그래밍
BOJ 1462 - 퀴즈쇼
풀이
dp[i][0]
:= 1~i 까지 문제를 푸는데, i를 풀고 나서 남은 코인의 갯수가 0개일 때의 최댓값
dp[i][1]
:= 1~i 가지 문제를 푸는데, i를 풀고 나서 남은 코인의 갯수와 상관없이 최댓값
위 처럼 2가지 dp를 저장한다고 하자.
먼저 dp[i][0]
를 생각해보자.
- i번 문제를 맞춰서 보너스 코인을 받아 코인을 모두 소모함.
dp[i-m][0] + (scoreAcc[i] - scoreAcc[i-m]) + bonus[i]
- i-m까지 문제를 풀고 나서 코인이 0개가 되었을 때의 최댓값 :=
dp[i-m][0]
- i-m+1 ~ i 까지의 문제를 모두 맞추고 i번 째 문제에서 보너스 점수를 받음 :=
(scoreAcc[i] - scoreAcc[i-m]) + bonus[i]
- i-m까지 문제를 풀고 나서 코인이 0개가 되었을 때의 최댓값 :=
- i번 문제를 틀려서 모든 코인을 잃음.
dp[i-1][1] - score[i]
i-1까지 최댓값에 i번째 문제를 틀려서 점수를 빼준다. 위와 같이 2가지 케이스가 된다.
그럼 이번에는 dp[i][1]
을 생각해보자.
- i번 맞추기
- i번을 맞춤으로써, M개 채움
- i번을 맞춰도 M개를 채우지 못 함.
- 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