予鈴

アウトプットとメモ書きの中間みたいな記事がたくさん出ます。

B - Neutralize

問題概要

N個の数列が与えられる。K個の連続する数字を選んで0にできる。\sum_{k = 1}^N A_{k}の最大値を求めよ。
B - Neutralize

解法

動的計画法
A_iが最大値となる数列に含まれるか、あるいは0になるか二通り存在するので、
dp[0][i] :=i番目の数字を使った時までの最大値
dp[1][i]  :=i番目の数字を使わない場合の最大値
とする。
更新は
A_i番目の数字を使うとすると、直前まで0になった場合が存在するので
dp[0][i] = max(dp[0][i-1],dp[1][i-1]) + A_i
同様に、A_{i-1}使わなかった場合と、A_iの数字を含めてちょうどK個の数字を使った場合があるので
dp[1][i] = max(dp[1][i-1],dp[0][i-k])

最初状態が3通り(使う、0になる列に含まれる、使わない)だと思ってたんですが、使う場合と使われない場合だけで漸化式を書けてしまってアって感じでした。

#include<bits/stdc++.h>
using ll  = long long;
#define int ll
#define rep(i,n) for(int i=0;i<n;i++)
#define INF (sizeof(int) == 4 ? (int)1e9:(int)1e18)
using namespace std;
template<typename Head, typename Value> auto vectors(const Head &head, const Value &v) { return vector<Value>(head, v); }
template<typename Head, typename... Tail> auto vectors(Head x, Tail... tail) { auto inner = vectors(tail...); return vector<decltype(inner)>(x, inner); }
signed main(){
    int n; int k;
    cin >> n >> k;
    auto dp = vectors(2,n,-INF);
    vector<int>v(n);
    for(auto & e : v) cin >> e;
    dp[0][0] = v[0]; dp[1][k-1] = 0LL;
    rep(x,n){
        if(x){
            dp[0][x] = max(dp[0][x-1], dp[1][x-1]) + v[x] ;
            if(x-k>=0)dp[1][x] = max(dp[1][x-1],dp[0][x-k]);
        }
    }
    cout << max(dp[0][n-1],dp[1][n-1]) << endl;
}