Official

D - アルバイトの計画 / Part-Time Job Planning Editorial by physics0523 Editorial for printing


動的計画法 (DP) を用いてこの問題を解くことができます。

\(dp[i][j]=\{\) \(i\) 日目までバイトするかどうかを決定して、それまでに \(j\) 回バイトをした場合の給料の最大値 \(\}\) という形の DP を行います。

\(dp[i][j]\) からの遷移は次の通りです。

  • \(dp[i+1][j]\) に \(dp[i][j]\) を遷移する。
    • \(i+1\) 日目にバイトをしない場合に該当します。
  • \(dp[i+D+1][j]\) に \(dp[i][j]+A_i\) を遷移する。
    • \(i+1\) 日目にバイトをして、その後 \(D\) 日間はバイトができない場合に該当します。

本解法の時間計算量は \(O(NK)\) です。

実装例 (C++):

#include<bits/stdc++.h>

using namespace std;
using ll=long long;

int main(){
  ll N,K,D;
  cin >> N >> K >> D;
  vector<ll> A(N);
  for(auto &nx : A){cin >> nx;}
  vector<vector<ll>> dp(N+1,vector<ll>(K+1,-1e18));
  dp[0][0]=0;
  for(ll i=0;i<N;i++){
    for(ll j=0;j<K;j++){
      dp[i+1][j]=max(dp[i+1][j],dp[i][j]);
      dp[min(N,i+D+1)][j+1]=max(dp[min(N,i+D+1)][j+1],dp[i][j]+A[i]);
    }
  }
  ll res=0;
  for(auto &nx : dp){
    res=max(res,(*max_element(nx.begin(),nx.end())));
  }
  cout << res << "\n";
  return 0;
}

posted:
last update: