树上阶梯nim

博客讲述了树上阶梯nim游戏的问题,这是一个两个人轮流操作的矿石运输游戏。玩家需将矿石从矿坑移动到父亲矿坑,最终目标是使得对方无法操作。通过分析阶梯nim的原理,得出结论:先将所有奇数深度节点的矿石数量异或,再异或这些异或结果,若最终异或值为0,先手必败,否则先手必胜。
摘要由CSDN通过智能技术生成
题面
在某个不知名的行星上蕴含着大量冰晶矿,Jim和他的好兄弟Swan自然不能放过这个赚钱的好机会。Jim在整个星球上开掘树型矿洞,每个矿坑之间都有矿道相连。Jim和Swan在每个矿坑开采了大量的矿石,现在他们面临一个新的问题,怎么把所有的矿石运出去。
已知,矿坑与矿坑之间形成了有向的树形结构,即除0号矿坑以外每个矿坑都有与其相连的父亲矿坑。Jim总共开采了 个矿坑并将其从0到 n-1 编号 ,每个矿坑都存有 val[i] 个单位的矿石。Jim和Swan每次操作都可以从某个矿坑移动至少1个单位的矿石到其父亲矿坑。Jim和Swan决定比试一下,由Jim开始轮流操作,最后不能操作的人输。Jim偷偷的找到了你,他想知道在两人都采取最优策略的情况下是否Jim能够赢得这场比试。
这个问题,可以简称它为:树上阶梯nim裸题,复杂度O(n)。
阶梯nim:有n个位置1…n,每个位置上有ai个石子。有两个人轮流操作。
操作步骤是:挑选1…n中任意一个存在石子的位置i,将至少1个石子移动至i−1位置(也就是最后所有石子都堆在在0这个位置)。谁不能操作谁输。求先手必胜还是必败。
相信大家都会做,就是把所有的奇数位置上的石子数量异或一下,若异或和为0,则先手输,否则后手输。现在在树上做的话,我们需要考虑一下阶梯nim这样做的原理是什么。
唉,感觉如果要考虑原理的话好难写,要写好多话,这里就直接给出一个结论吧。
(由于题目中需要把所有矿石移动到节点0,所以,设节点0的深度为0)那么结论就是:先把所有深度为1,3,5…的val[i]异或起来,记录在sum[i]中(sum[1]=所有深度为1的节点的val异或和,sum[3]为所有深度为3的节点的val异或和),然后把sum[1],sum[3],sum[5]…异或起来,记录为ans。此时,ans为0,先手必败,否则先手必胜。
当清楚了解了阶梯nim的原理后,树上阶梯nim应该很好理解了,自己猜一波结论应该也可以猜出来了。(相当于做了一个二维的阶梯nim)
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int T,n,u,maxn,ans;
int a[N],d[N],sum[N];
int cnt,head[N];
struct edge{
   int next,to;}e[N<<1];

inline void add(int u,int v)
{
   
	cnt++;
	e[cnt].next=head[u
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值