题意:

使用魔法或者斩击消除数组。

题解:

  • 假设这道没有魔法这项能力的话,

现在有一个数组,要如何使用最少次数的斩击才能使数组的每个数都消除?

4,7,8,3,1,0,4,5

首先可以想到,数组的第一个数必须要先消除,才能保证最优,其次是第二个数,再到第三个……,因此不使用魔法的话,只要进行贪心就能得到最少次数的斩击数。

  • 将魔法这项技能加进来,假设将下面数组中的这两个数用魔法消除(数组中字体加粗的那两个):

4,7,8,3,1,0,4,5

求解最少斩击数,就应该是1 ~ 3和6 ~ 7(数组的下标从1开始)这两段的最少斩击数,对于求解这两段的最少斩击数,可以采用上面的贪心去求解。

如果用魔法消除的是aia_iaiai+1a_{i+1}ai+1 ,那么斩击数就是数组111~i1{i-1}i1i+2{i+2}i+2 ~ nnn区间的最少斩击数,对于数组的斩击数,我们是可以预处理出来的,使用perperper数组代表1 ~ nnn的斩击数,sursursur数组代表nnn ~ 1的斩击,所以这题的结果就是min(per[i1],sur[i+2])min(per[i-1],sur[i+2])min(per[i1],sur[i+2])

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
typedef long long ll;
ll pre[N],sur[N],a[N],b[N];

int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]),b[i]=a[i];
	
	if(n<=2)
	{
		puts("0");
		return 0;
	}
	
	for(int i=1;i<=n;i++)
	{
		if(a[i]>0)
		{
			pre[i]=pre[i-1]+a[i];
			a[i+1]-=a[i];a[i+2]-=a[i];
		}
		else pre[i]=pre[i-1];
	}
	for(int i=n;i>=2;i--)
	{
		if(b[i]>0)
		{
			sur[i]=sur[i+1]+b[i];
			b[i-1]-=b[i];b[i-2]-=b[i];
		}
		else sur[i]=sur[i+1];
	}
	
	/*for(int i=1;i<=n;i++)
		printf("%4d ",pre[i]);printf("\n");
	for(int i=1;i<=n;i++)
		printf("%4d ",sur[i]);printf("\n");*/
	ll ans=pre[n];
	for(int i=1;i<=n;i++)
		ans=min(ans,pre[i-1]+sur[i+2]);
	printf("%lld\n",ans);
	return 0;
}