HDU 5996 BestCoder Round #90 1002 dingyeye loves stone 博弈


题意:
有一棵n个节点的有根树,节点编号为0到n-1,根为0号节点。游戏开始时,第i个节点上有a[i]个石子。两位玩家轮流操作,每次操作玩家可以选择一个节点,并将该节点上的一些石子(个数不能为0)移动到它的父亲节点上去。如果轮到某位玩家时,该玩家没有任何合法的操作可以执行,则判负。
你在游戏中执先手,你想知道当前局面你能否必胜。

思路:
肯定是nim啊,nim肯定和异或有关啊。
其实上面说的也不一定对,先考虑只有深度为一的情况,不难发现当各节点值的异或和为0时是必败态,不然就是必胜态。
然后考虑深度不一定只为一的情况,有这样的策略,如果先手操作了深度为偶数的节点的值(操作后这个值在奇数节点),我们也可以接着操作这个值(把这个值移到它上面的偶数节点)。因为根节点的深度为0(当然这是人为定义的……),所以偶数节点的值总是可以被上述策略移到根节点,所以考虑奇数节点的值就好了。
说的很轻松,但直接想可能还是有点难,建议读者可以多想几个情况考虑下,便于理解。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define MS(x,y) memset(x,y,sizeof(x))
const int MAXN=1e5+5;
struct Edge{
    int v,nxt;
}edge[MAXN];
int head[MAXN],edgenum;
void addedge(int u,int v){
    edge[edgenum].v=v;
    edge[edgenum].nxt=head[u];
    head[u]=edgenum++;
}

int n,mx;
int dep[MAXN],val[MAXN];
void dfs(int u,int d){
    mx=max(mx,d);
    dep[d]^=val[u];
    for(int i=head[u];~i;i=edge[i].nxt){
        int &v=edge[i].v;
        dfs(v,d+1);
    }
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        edgenum=mx=0;
        for(int i=0;i<n;++i) head[i]=-1,dep[i]=0;
        for(int i=1,u;i<n;++i){
            scanf("%d",&u);
            addedge(u,i);
        }
        for(int i=0;i<n;++i){
            scanf("%d",val+i);
        }
        dfs(0,0);
        int ans=0;
        for(int i=1;i<=mx;i+=2){
            ans^=dep[i];
        }
        if(ans) puts("win");
        else puts("lose");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值