bzoj2000 [Hnoi2010]stone 取石头游戏
Description
A 公司正在举办一个智力双人游戏比赛----取石子游戏,游戏的获胜者将会获得 A 公司提供的丰厚奖金,因此吸引了来自全国各地的许多聪明的选手前来参加比赛。
与经典的取石子游戏相比,A公司举办的这次比赛的取石子游戏规则复杂了很多:
总共有N堆石子依次排成一行,第i堆石子有 ai个石子。
开始若干堆石子已被 A公司故意拿走。
然后两个玩家轮流来取石子,每次每个玩家可以取走一堆中的所有石子,但有一个限制条件:一个玩家若要取走一堆石子,则与这堆石子相邻的某堆石子已被取走(之前被某个玩家取走或开始被A公司故意拿走)。注意:第 1堆石子只与第 2堆石子相邻,第N堆石子只与第N-1堆石子相邻,其余的第 i堆石子与第i-1堆和第 i+1 堆石子相邻。
所有石子都被取走时,游戏结束。谁最后取得的总石子数最多,谁就获得了这场游戏的胜利。
作为这次比赛的参赛者之一,绝顶聪明的你,想知道对于任何一场比赛,如果先手者和后手者都使用最优的策略,最后先手者和后手者分别能够取得的总石子数分别是多少。
Input
第一行是一个正整数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。
Output
仅包含一行,为两个整数,分别表示都使用最优策略时,最后先手者和后手者各自能够取得的总石子数,并且两个整数间用一个空格隔开。
Sample Input
1 2 0 3 7 4 0 9
Sample Output
正解:博弈论+链表。
这道题的难点在于分析博弈者的心理。
双方的目标就是使自己-别人的石子数差最大化。
可以看出,石子堆分为两个栈和若干个双端队列。
如果所有元素在每一个容器中都是递减的,那么先手和后手显然可以每次都取最大元素来保证自己利益的最大化。
但是现在不是这样,不过我们可以把这个数列化简一下。
如果序列最左端是$A,B...$或最右端是$...B,A$,且$B\leq A$。
那么双方在有其它方案时都不会愿意先取走$B$,故这种情况可以留到博弈的最后。
由于石子数是确定的,可以直接推出最后谁取到了$A$,算出相应差值。
由于可以留到游戏的最后,此时删除这两堆并不影响两人之前的决策。
如果有一段 $...A,B,C...$且满足$A\leq B,C\leq B$。
那么我们直接把 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$。
我们用链表实现化简,就能把石子变成递减的情况,然后直接排序取石子就行了。
#include <bits/stdc++.h>
#define il inline
#define RG register
#define ll long long
#define N (1000005) using namespace std; int b[N],l[N],r[N],n,h,t,ok,cnt,tmp;
ll a[N],c[N],sum,dif; il int gi(){
RG int x=,q=; RG char ch=getchar();
while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar();
while (ch>='' && ch<='') x=x*+ch-,ch=getchar();
return q*x;
} il void del(RG int x){
RG int L=l[x],R=r[x];
if (L) r[L]=R,l[x]=;
if (R<=n) l[R]=L,r[x]=n+;
return;
} int main(){
#ifndef ONLINE_JUDGE
freopen("stone.in","r",stdin);
freopen("stone.out","w",stdout);
#endif
n=gi(),h=,t=n,ok=;
for (RG int i=;i<=n;++i)
a[i]=gi(),sum+=a[i],b[i]=!a[i],cnt^=!b[i],l[i]=i-,r[i]=i+;
while (ok && h<t){
ok=;
while (h<t && !b[h] && !b[r[h]] && a[h]>=a[r[h]]){
cnt?dif+=a[h]-a[r[h]]:dif+=a[r[h]]-a[h];
tmp=r[r[h]],del(r[h]),del(h),h=tmp,ok=;
}
while (h<t && !b[t] && !b[l[t]] && a[t]>=a[l[t]]){
cnt?dif+=a[t]-a[l[t]]:dif+=a[l[t]]-a[t];
tmp=l[l[t]],del(l[t]),del(t),t=tmp,ok=;
}
for (RG int i=h;i<=t;i=r[i]){
if (b[i] || !l[i] || r[i]==n+ || b[l[i]] || b[r[i]]) continue;
if (a[i]<a[l[i]] || a[i]<a[r[i]]) continue;
if (h==l[i]) h=i; if (t==r[i]) t=i;
a[i]=a[l[i]]+a[r[i]]-a[i],del(l[i]),del(r[i]),ok=;
}
}
cnt=; for (RG int i=h;i<=t;i=r[i]) if (!b[i]) c[++cnt]=a[i];
sort(c+,c+cnt+),reverse(c+,c+cnt+);
for (RG int i=;i<=cnt;++i) i&?dif+=c[i]:dif-=c[i];
printf("%lld %lld\n",(sum+dif)>>,(sum-dif)>>); return ;
}
bzoj2000 [Hnoi2010]stone 取石头游戏的更多相关文章
- [HNOI2010]STONE取石头游戏
题目描述 A 公司正在举办一个智力双人游戏比赛----取石子游戏,游戏的获胜者将会获得 A 公司提供的丰厚奖金,因此吸引了来自全国各地的许多聪明的选手前来参加比赛. 与经典的取石子游戏相比,A公司举办 ...
- BZOJ.2000.[HNOI2010]stone取石头游戏(博弈)
BZOJ 洛谷 低估这道神题了_(:з」∠)_ MilkyWay好狠啊(小声) \(Description\) 有一些数字,被分成若干双端队列(从两边都可以取)和最多两个栈(只能从某一边一个一个取)的 ...
- 【BZOJ2000】[HNOI2000]取石头游戏(贪心,博弈论)
[BZOJ2000][HNOI2000]取石头游戏(贪心,博弈论) 题面 BZOJ 洛谷 题解 这题好神仙啊,窝不会QaQ. 假装一下只有三个元素\(a_{i-1},a_i,a_{i+1}\),并且满 ...
- [luogu] P3210 [HNOI2010]取石头游戏(贪心)
P3210 [HNOI2010]取石头游戏 题目描述 A 公司正在举办一个智力双人游戏比赛----取石子游戏,游戏的获胜者将会获得 A 公司提供的丰厚奖金,因此吸引了来自全国各地的许多聪明的选手前来参 ...
- luogu P3210 [HNOI2010]取石头游戏
传送门 不会结论做个鬼系列 题意其实是在头尾(最多)两个栈以及中间一些双端队列依次取数,然后每个人都要最大化自己的价值 有一个结论,如果一段序列中,出现了三个相邻位置\(A,B,C\),满足\(A\l ...
- 题解 洛谷 P3210 【[HNOI2010]取石头游戏】
考虑到先手和后手都使用最优策略,所以可以像对抗搜索一样,设 \(val\) 为先手收益减去后手收益的值.那么先手想让 \(val\) 尽可能大,后手想让 \(val\) 尽可能小. 继续分析题目性质, ...
- HDU 1729 Stone Game 石头游戏 (Nim, sg函数)
题意: 有n个盒子,每个盒子可以放一定量的石头,盒子中可能已经有了部分石头.假设石头无限,每次可以往任意一个盒子中放石头,可以加的数量不得超过该盒中已有石头数量的平方k^2,即至少放1个,至多放k^2 ...
- Games:取石子游戏(POJ 1067)
取石子游戏 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 37662 Accepted: 12594 Descripti ...
- CH 3401 - 石头游戏 - [矩阵快速幂加速递推]
题目链接:传送门 描述石头游戏在一个 $n$ 行 $m$ 列 ($1 \le n,m \le 8$) 的网格上进行,每个格子对应一种操作序列,操作序列至多有 $10$ 种,分别用 $0 \sim 9$ ...
随机推荐
- java 如何下载jar包
随着maven工具的使用,我们已经不再需要辛苦的找jar包,也不需要再买会员去下载jar包,但是还有一些同学,不知道怎么下载jar包,下面我给大家介绍一下,如何潇洒的找到自己想要的jar包. 首先,访 ...
- 很小的一个函数执行时间调试器Timer
对于函数的执行性能(这里主要考虑执行时间,所耗内存暂不考虑),这里写了一个简单的类Timer,用于量化函数执行所耗时间. 整体思路很简单,就是new Date()的时间差值.我仅仅了做了一层简单的封装 ...
- document文档流详解
html页面下载完默认会打开一个文档流document对象(调用document.open,此时浏览器标题左边会显示加载中图标),开始从上往下渲染内容,渲染完成调用document.close关闭渲染 ...
- 利用canvas制作图片(可缩放和平移)+相框+文字
前言: 公司一个售前问我能不能用H5做一个手机拍照,给相片添加相框和添加文字上传到服务器的功能,我当时一琢磨觉得可行,就利用空余时间做了一个demo,去掉了拍照和上传,如果以后有机会,会给补上,当然对 ...
- 版本控制器之SVN
1.开发中的实际问题 1.1 小明负责的模块就要完成了,就在即将Release之前的一瞬间,电脑突然蓝屏,硬盘光荣牺牲!几个月来的努力付之东流——需求之一:备份! 1.2 这个项目中需要一个很复杂的功 ...
- Sqoop迁移Hadoop与RDBMS间的数据
Sqoop是用来实现结构型数据(如:关系型数据库RDBMS)和Hadoop之间进行数据迁移的工具.它充分利用了MapReduce的并行特点以批处理的方式加快数据的传输,同时也借助MapReduce实现 ...
- 廖雪峰JavaScript练习题2
请把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字.输入:['adam', 'LISA', 'barT'],输出:['Adam', 'Lisa', 'Bart'] 肯定有更简单的方法, ...
- sql server or Oracle: table MS_Description
--SQL Server表描述 及 字段描述的增.删.改.查询 --sql server 2000系统表sysproperties在SQL 2008中无效的问题 今天无意中在网上发现Sqlserver ...
- javascript时间格式转换(今天,昨天,前天)
function transDate() { var $time =document.getElementById("share-time"); var date = $time. ...
- Windows 64位下安装Redis教程
Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型. Key-Value数据库,并提供多种语言的API. 一.下载 地址:Download redis-latest ...