• [HNOI2010]STONE取石头游戏


    题目描述

    A 公司正在举办一个智力双人游戏比赛----取石子游戏,游戏的获胜者将会获得 A 公司提供的丰厚奖金,因此吸引了来自全国各地的许多聪明的选手前来参加比赛。

    与经典的取石子游戏相比,A公司举办的这次比赛的取石子游戏规则复杂了很多:

    l 总共有N堆石子依次排成一行,第i堆石子有 ai个石子。

    l 开始若干堆石子已被 A公司故意拿走。

    l 然后两个玩家轮流来取石子,每次每个玩家可以取走一堆中的所有石子,但有一个限制条件:一个玩家若要取走一堆石子,则与这堆石子相邻的某堆石子已被取走(之前被某个玩家取走或开始被A公司故意拿走)。注意:第 1堆石子只与第 2堆石子相邻,第N堆石子只与第N-1堆石子相邻,其余的第 i堆石子与第i-1堆和第 i+1 堆石子相邻。

    l 所有石子都被取走时,游戏结束。谁最后取得的总石子数最多,谁就获得了这场游戏的胜利。

    作为这次比赛的参赛者之一,绝顶聪明的你,想知道对于任何一场比赛,如果先手者和后手者都使用最优的策略,最后先手者和后手者分别能够取得的总石子数分别是多少。

    输入输出格式

    输入格式:

    第一行是一个正整数N,表示有多少堆石子。输入文件第二行是用空格隔开的N个非负整数a1, a2, ..., aN,其中ai表示第i堆石子有多少个石子,ai = 0表示第i堆石子开始被A公司故意拿走。输入的数据保证0<=ai<=100,000,000,并且至少有一个i使得ai = 0。30%的数据满足2<=N<=100,100%的数据满足2<=N<=1,000,000。

    输出格式:

    仅包含一行,为两个整数,分别表示都使用最优策略时,最后先手者和后手者各自能够取得的总石子数,并且两个整数间用一个空格隔开。

    输入输出样例

    输入样例#1: 复制
    输出样例#1: 复制
    者取得9 + 1 + 7 = 17个石子,后手者取得2 + 4 + 3 = 9个石子。
    本题和一般的博弈问题不一样。本题不讨论输赢,只让选手得到尽量多的石子。
    由于双方最终石子数之和是确定的,双方的目标就是使自己-别人的石子数差最大
    化。
    首先我们可以抽象问题:
    有两个栈,若干个双头队列,总长度不超过$10^{6}$
    每次可以从栈顶取一个数,也可以从双头队列选一端取一个数。
    $2$人轮流以最大化自己数字和的目标取数,问最终结果。
    如果只有一个栈,那么取法是一定的。
    如果只有一个队列,如果是奇数个,取法也是一定的。如果是偶数个,先手会取
    max(奇数位的和,偶数位的和).
    本题的关键难点是组合策略。
    如果可取元素都是递减的,比如
    1 2 3 0 2 1 2 0 4 1
    容易发现先手只要贪心地从能取的元素里面拣最大的取走即可。
    这样不会给后手好情况。
    由于每次一定可以取全场最大值,所以只要一次排序然后交替取值即可。
    4 3 2 2 2 1 1 1
    如果不是这样,我们可以通过 2 个操作来化简数列:
    1. 如果最左端是 A B.. 或者最右端是..B A, 且 A>=B
    那么双方在有其它方案时都不会愿意先取走 B,故这种情况可以留到博弈的最后。
    由于石子数是确定的,可以直接推出最后谁取到了 A,算出相应差值。
    由于可以留到游戏的最后,此时删除这两堆并不影响两人之前的决策。
    2. 如果有一段 ..A B C..
    且满足 B>=A B>=C
    那么我们直接把 ABC 替换成一个 A+C-B 即可。
    我们可以这样想:选 A,B,C 的时候是因为没有更好的决策而被迫选的。事实上当
    全场没有大于 A+C-B 的石子堆可以直接取时,才会考虑取 A,C 中的一个。那么不管第
    一次取 A,B,C 中的元素是从哪边,后手一定也没有别的更好的选择,既然先手选 A/C
    都已是被迫了,所以后手选 B 一定不会是差的。留下来的一个也一定是当前不差的选
    择。故先手一定取走 A+C,后手取走 B。从对分数差的贡献来看,我们可以直接把 A,B,C
    代替成 A+C-B
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 using namespace std;
     7 typedef long long lol;
     8 int n,top,pd[1000001],l,r,cnt,tot;
     9 lol st[1000001],ans,sum,a[1000001];
    10 bool cmp(lol a,lol b)
    11 {
    12   return a>b;
    13 }
    14 int main()
    15 {int i;
    16   cin>>n;
    17   for (i=1;i<=n;i++)
    18     {
    19       scanf("%lld",&st[++top]);
    20       sum+=st[top];
    21       if (st[top]==0) pd[top]=1;
    22       tot+=(bool)st[top];
    23       while (top>2&&(!pd[top])&&(!pd[top-1])&&(!pd[top-2])&&(st[top-1]>=st[top])&&(st[top-1]>=st[top-2]))
    24     {
    25       st[top-2]=st[top]+st[top-2]-st[top-1];
    26       top-=2;
    27     }
    28     }
    29   for (l=1;(!pd[l])&&(!pd[l+1])&&(st[l]>=st[l+1]);l+=2)
    30     ans+=tot&1?st[l]-st[l+1]:st[l+1]-st[l];
    31   for (r=top;(!pd[r])&&(!pd[r-1])&&(st[r]>=st[r-1]);r-=2)
    32     ans+=tot&1?st[r]-st[r-1]:st[r-1]-st[r];
    33   for (i=l;i<=r;i++)
    34     if (pd[i]==0) a[++cnt]=st[i];
    35   sort(a+1,a+cnt+1,cmp);
    36   for (i=1;i<=cnt;i++)
    37     {
    38       if (i&1) ans+=a[i];
    39       else ans-=a[i];
    40     }
    41   cout<<(sum+ans)/2<<' '<<(sum-ans)/2<<endl;
    42 }
  • 相关阅读:
    eWebEditor漏洞
    远程连接SQL Server
    eWebEditor漏洞
    【Demo 0009】绘图对象调色板
    【Demo 0001】 获取命令行参数
    【Demo 0007】绘图对象 画笔
    【Demo 0005】Win32 程序结构封装
    【Demo 0006】图形绘制基础
    【Demo 0008】绘图对象–画刷
    【Demo 0004】Windows 消息机制(2)
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8555129.html
Copyright © 2020-2023  润新知