Official

D - Poisonous Full-Course Editorial by physics0523


動的計画法でこの問題を解くことを考えます。すると、どのような情報を保持するべきでしょうか?

結論から言うと、以下の DP テーブルを作成することでこの問題を解くことができます。

  • \(dp[\) 料理 \(i\) \(][\) 高橋くんの状態 \(j\) \(]\)
    • 料理 \(i\) までの料理を食べるか下げてもらうか選択した時に、高橋くんの状態が \(j\) ( \(0\) … 高橋くんがお腹を壊していない、 \(1\) … 高橋くんがお腹を壊している ) である時の、食べた料理の美味しさの総和の最大値

この問題が解けなかった方は、上で 「どのような DP テーブルを作れば解けるか」を示したので、「 DP テーブルの遷移はどうするべきか」を考えて実装してみてください。動的計画法の良い練習になります。

遷移の解説

  // 実装例では料理を 0-indexed で取り扱っていることに注意
  // DP テーブルの初期化
  for(long long i=0;i<=n;i++){
    dp[i][0]=-4e18; // dp[i][0] = -∞
    dp[i][1]=-4e18; // dp[i][1] = -∞
  }
  dp[0][0]=0; // 最初、高橋くんはお腹を壊していない

  for(long long i=0;i<n;i++){
    // i 番目の料理を食べる場合の遷移
    if(x[i]==0){
      dp[i+1][0]=max(dp[i][0],max(dp[i][0],dp[i][1])+y[i]);
    }
    else{
      dp[i+1][1]=max(dp[i][1],dp[i][0]+y[i]);
    }
    // i 番目の料理を食べない場合の遷移
    dp[i+1][0]=max(dp[i+1][0],dp[i][0]);
    dp[i+1][1]=max(dp[i+1][1],dp[i][1]);
  }


実装例(C++):

#include<bits/stdc++.h>

using namespace std;

long long dp[300005][2];

int main(){
  long long n;
  cin >> n;
  vector<long long> x(n),y(n);
  for(long long i=0;i<n;i++){
    cin >> x[i] >> y[i];
  }

  for(long long i=0;i<=n;i++){
    dp[i][0]=-4e18;
    dp[i][1]=-4e18;
  }
  dp[0][0]=0;

  for(long long i=0;i<n;i++){
    if(x[i]==0){
      dp[i+1][0]=max(dp[i][0],max(dp[i][0],dp[i][1])+y[i]);
    }
    else{
      dp[i+1][1]=max(dp[i][1],dp[i][0]+y[i]);
    }

    dp[i+1][0]=max(dp[i+1][0],dp[i][0]);
    dp[i+1][1]=max(dp[i+1][1],dp[i][1]);
  }
  cout << max(dp[n][0],dp[n][1]) << "\n";
  return 0;
}

posted:
last update: