次のような動的計画法を考えます.
時刻 ii における体力 jj のときの得られる賞金の合計の最大をdp[i][j]dp[i][j] としたとき,遷移は

  • モンスターを討伐する: dp[i+1][j1]=max(dp[i][j1],dp[i][j]+Ai)(j0)dp[i+1][j-1] = \max(dp[i][j-1], dp[i][j]+A_i) \quad (j \ne 0)
  • 休憩する: dp[i+1][M]=max(dp[i+1][M],dp[i][j])dp[i+1][M] = \max(dp[i+1][M], dp[i][j])
  • 何もしない: dp[i+1][j]=max(dp[i+1][j],dp[i][j])dp[i+1][j] = \max(dp[i+1][j], dp[i][j])

となり,答えは max0jMdp[N+1][j]\max \limits_{0 \le j \le M} dp[N+1][j] となります. しかしこの動的計画法の時間計算量は O(NM)O(NM) と間に合いません.

また「何もしない」を選ぶとき「休憩する」を選べば良いため,「何もしない」は選ばなくても良いことが分かります.

これをいわゆる貰いdpに変換すると

  • モンスターを討伐する: dp[i][j]=dp[i1][j+1]+Ai(jM)dp[i][j] = dp[i-1][j+1] + A_i \quad (j \ne M)
  • 休憩する: dp[i][M]=max0jMdp[i1][j]dp[i][M] = \max \limits_{0 \le j \le M} dp[i-1][j]

になります.

ここで時刻 ii に「休憩する」をしたときの得られなかった賞金の合計の最小を dp[i]dp'[i] としたとき, dp[i][j]=k=1iAkdp[ij]dp[i][j] = \sum_{k=1}^{i} A_k - dp'[i-j] より, dp[i]dp'[i] の遷移は

  • 休憩する: dp[i]={0ifi0min0jMdp[ij1]+Aiif1iNdp'[i] = \begin{cases} 0 &\text{if} \: i \le 0 \\ \min \limits_{0 \le j \le M} dp'[i-j-1] + A_i &\text{if} \: 1 \le i \le N \end{cases}

となり,答えは i=1NAimin0iMdp[Ni]\sum_{i=1}^{N} A_i - \min \limits_{0 \le i \le M} dp'[N-i] となります.

Bi={ij10jM}B_i = \{i-j-1 \: | \: 0 \le j \le M\} としたとき Bi=(Bi1{iM2}){i1}B_i = (B_{i-1} \setminus \{i-M-2\}) \cup \{i-1\} であるため,multiset等を用いることにより minbBidp[b]\min \limits_{b \in B_i} dp'[b]O(logM)O(\log M) で求めることができます. よって時間計算量 O((N+M)logM)O((N+M)\log M) となり間に合います.

また,遅延セグメント木を用いてインラインDPをすることでも解くことが可能です.

想定ソースコード

C++
Python3