传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2000
大家用心“感受”一下CA娘的贪心策略吧(我觉得我讲不清)
http://blog.csdn.net/CreationAugust/article/details/48246581
大概思路就是:
如果出现了形如
ai−1≤ai≤ai+1
的,那么双方的最优方案是确定的,就是先动手的取两边
如果在两端出现了形如
ai−1≤ai
那么假如有人取走了
ai
,那么另一个人一点会取走
ai+1
(简单地反证一下应该就能得出这结论的正确性)
a是收益,而不是原始读入。
在处理过程中,我们会把原始读入不断转变为差值来表示收益,比如对于前文举的第一种情况,就会把三个收益合并成
ai−1+ai+1−ai
然后两端的合并(也就是前文第二种情况)是可以根据奇偶性判断应该把收益给谁的。
最后剩下的部分就会发现是一个纯粹的贪心。
结构是每一段的较大值暴露在外(所以可以直接sort然后取)。
#include<stdio.h>
#include<algorithm>
#include<iostream>
#define N 1000005
using namespace std;
typedef long long ll;
int n,top,ed,ct,l,r;
bool use[N];
ll ans,tot,st[N],a[N];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lld",st+ ++top);
tot+=st[top];
if (st[top]==0) use[top]=1;
ct^=!use[top];
while (2<top && (!use[top]) && (!use[top-1]) && (!use[top-2]) && st[top]<=st[top-1] && st[top-2]<=st[top-1])
{
st[top-2]=st[top]+st[top-2]-st[top-1];
top-=2;
}
}
for (l=1;(!use[l]) && (!use[l+1]) && st[l+1]<=st[l];l+=2) ans+=(ct?1:-1)*(st[l]-st[l+1]);
for (r=top;(!use[r]) && (!use[r-1]) && st[r-1]<=st[r];r-=2) ans+=(ct?1:-1)*(st[r]-st[r-1]);
for (int i=l;i<=r;i++) if (!use[i]) a[++ed]=st[i];
sort(a+1,a+ed+1,greater<ll>());
for (int i=1;i<=ed;i++) ans+=(i&1)?a[i]:-a[i];
printf("%lld %lld",tot+ans>>1,tot-ans>>1);
}