Official

D - Bonus EXP Editorial by mechanicalpenciI


この問題は動的計画法によって解くことができます。

\(k\) 匹目までのモンスターと出会い、偶数(\(0\) を含む)匹倒した時に得られる経験値の最大値」と「\(k\) 匹目までのモンスターと出会い、奇数匹倒した時に得られる経験値の最大値」(そのようなことが不可能な場合は \(-\infty\) )をそれぞれ \(dp_{even}[k]\), \(dp_{odd}[k]\) とします。

最初、\(dp_{even}[0]=0\), \(dp_{odd}[0]=-\infty\) です。
ここで、\(1\leq i\leq N\) について、\(i\) 匹目のモンスターから得られる経験値は、

  • 高橋君が逃がすと倒すのどちらを選択したか
  • (倒すことを選択した際)それまでに倒したモンスターの数が偶数か奇数か

にのみ依存して決まることに注意します。さらに、「\(i\) 匹目までのモンスターと出会い、偶数匹倒す」パターンは以下のどちらかしかありません。

  • \(k-1\) 匹目までの間に偶数匹倒し、\(k\) 匹目のモンスターを逃がした場合
  • \(k-1\) 匹目までの間に奇数匹倒し、\(k\) 匹目のモンスターを倒した場合

よって、\(dp_{even}[i-1]\), \(dp_{odd}[i-1]\) の値が求まっている時、\(dp_{even}[i]\) は、

\[ dp_{even}[i]=\max(dp_{even}[i-1],dp_{odd}[i-1]+2A_i) \]

として求めることができます。同様に \(dp_{odd}[i]\) は、

\[ dp_{odd}[i]=\max(dp_{odd}[i-1],dp_{even}[i-1]+A_i) \]

として求めることができます。
最終的な答えは \(\max(dp_{even}[N],dp_{odd}[N])\) となります。

このときの計算量は \(O(N)\) であり、今回の制約下で十分高速です。
よってこの問題を解くことができました。

C++ による実装例:

#include <bits/stdc++.h>

using namespace std;

#define INF (long long)1e+18

int main(void){
	int n;
	long long x,dp0=0,dp1=-INF,tmp;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>x;
		tmp=dp0;
		dp0=max(dp1+2*x,dp0);
		dp1=max(tmp+x,dp1);
	}
	cout<<max(dp0,dp1)<<endl;
	return 0;
}

posted:
last update: