문제 링크

발상

어느 지점에서든 점프를 중지하고 현재 점수로 끝낼 수 있다 = 모든 지점에서 최댓값을 갱신한다. 어느 지점에서든 시작할 수 있다 = 현재 지점에서 고를 수 있는 값들이 전부 음수일 경우, 선택하지 모두 선택하지 않고 현재 징검 다리의 점수만을 취할 수 있다. 로 치환해 읽을 수 있다. 풀이의 편의를 위해 왼쪽 첫번째 징검다리에서 시작해 오른쪽 마지막 징점다리까지 점프한다고 가정하자. 현재 징검다리 인덱스 로 도착할 수 있는 징검다리 인덱스 범위는 이다. (해당 범위의 최적값 중 최대 점수) + (현재 징검다리 점수) 가 현재 징검다리를 밟으면서 얻을 수 있는 최적값이 된다. 단, 처음에 써놨듯이 범위 내 값들이 전부 음수인 경우, 굳이 취할 이유가 없으므로 현재 징검다리에서 시작하는 예외적 선택지만 추가로 고려하면 된다.

점화식

코드

#include <iostream>
#include <algorithm>
#include <vector>
#include <deque>
using namespace std;
using ll = long long;
struct node {
    ll i, v;
};
int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int n, k; cin >> n >> k; vector<ll> arr(n + 1), dp(n + 1); deque<node> dq;
    ll s = 0;
    for (int i = 1; i <= n; i++) {
        cin >> arr[i];        
        s += arr[i];
    }
    ll mx = -1e15;    
    for (int i = 1; i <= n; i++) {
        while (!dq.empty() && i - dq.front().i > k) dq.pop_front();
        ll p = dq.empty() ? 0 : dq.front().v;        
        dp[i] = (p > 0 ? p : 0) + arr[i]; // 이전 배열 최적값이 음수인 경우 고려할 가치가 없음 ( 현재 징검다리에서 시작하는게 더 나은 경우 ) 
        while (!dq.empty() && dq.back().v < dp[i]) dq.pop_back();
        dq.push_back({ i, dp[i] });
        mx = mx > dp[i] ? mx : dp[i];
    }
    cout << mx;
    return 0;
}