【BZOJ】2000: [Hnoi2010]stone 取石头游戏

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2000

大家用心“感受”一下CA娘的贪心策略吧(我觉得我讲不清)
http://blog.csdn.net/CreationAugust/article/details/48246581

大概思路就是:
如果出现了形如 ai1aiai+1 的,那么双方的最优方案是确定的,就是先动手的取两边
如果在两端出现了形如 ai1ai 那么假如有人取走了 ai ,那么另一个人一点会取走 ai+1
(简单地反证一下应该就能得出这结论的正确性)
a是收益,而不是原始读入。
在处理过程中,我们会把原始读入不断转变为差值来表示收益,比如对于前文举的第一种情况,就会把三个收益合并成 ai1+ai+1ai
然后两端的合并(也就是前文第二种情况)是可以根据奇偶性判断应该把收益给谁的。
最后剩下的部分就会发现是一个纯粹的贪心。
结构是每一段的较大值暴露在外(所以可以直接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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值