Jinsoolve.

Categories

Tags

8월 안에는 꼭...

Portfolio

About

백준 1462 - 퀴즈쇼

Created At: 2024/12/26

2 min read

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

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

  1. i번 맞추기
  2. i번을 맞춤으로써, M개 채움
  3. i번을 맞춰도 M개를 채우지 못 함.
  4. 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]이 몇 개의 코인을 모았는지 신경쓸 필요가 없다.

코드

cpp
#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; }

관련 포스트가 13개 있어요.

백준 28129 - 2022 APC가 어려웠다고요?

위 포스트는 백준 28129 - 2022 APC가 어려웠다고요?의 풀이입니다. dp[i][j] := i번째 수가 j가 되는 경우의 수 dp[i][j]=∑k=max(j−k,a[i−…

2025/03/28

NEW POST
profile

김진수

Currently Managed

Currently not managed

© 2026. jinsoolve all rights reserved.