codeforces 812 E. Sagheer and Apple Tree(树+尼姆博弈)

题目链接:http://codeforces.com/contest/812/problem/E

题意:有一颗苹果树,这个苹果树所有叶子节点的深度要不全是奇数,要不全是偶数,并且包括根在内的所有节点上都有若干个苹果,现有两个,每个人可以吃掉某个叶子节点上的部分苹果(不能不吃),或者将某个非叶子结点上的部分苹果移向它的孩子(当然也不能不移),吃掉树上最后一个苹果的人获胜。后手可以在游戏开始之前交换任意两个不同的节点的苹果,输出交换后能使得后手胜利的交换总数。

题解:这题挺友善的所有叶子结点的深度奇偶性是一样的,首先考虑到叶子结点是奇数步的,显然不论先手怎么操作,后手总是能吃掉这些苹果比较显然不解释了。然后就是偶数步时,先手操作一次偶数步时显然偶数步就会变成奇数步,也就是说移动的这部分苹果肯定是先手吃到的。于是就转换到了裸的尼姆博弈,什么是尼姆博弈不知道的可以去百度一下。于是这题只要将所有偶数步的节点上的苹果异或一下如果结果是0那么后手胜利否则先手胜利。

然后就是怎么处理交换了,如果ans=0(ans表示异或结果)那么只要在偶数步与奇数步中交换相同的数即可,还有就是偶数步中与奇数步中分别自行交换。

如果ans!=0那么只要遍历一遍偶数步的点找奇数点中苹果数为ans^val[i]的个数即可。

#include <iostream>
#include <string>
#include <cstdio>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const int M = 1e5 + 10;
map<int , int>num;
vector<int>vc[M];
int ans , val[M] , deep[M] , maxdeep;
void dfs(int u , int pre , int d) {
    int len = vc[u].size();
    deep[u] = d;
    maxdeep = max(maxdeep , d);
    for(int i = 0 ; i < len ; i++) {
        int v = vc[u][i];
        if(v == pre) continue;
        dfs(v , u , d + 1);
    }
}
int main() {
    int n;
    scanf("%d" , &n);
    num.clear();
    for(int i = 0 ; i <= n ; i++) vc[i].clear();
    for(int i = 1 ; i <= n ; i++) {
        int gg;
        scanf("%d" , &gg);
        val[i] = gg;
        num[gg]++;
    }
    for(int i = 1 ; i < n ; i++) {
        int gg;
        scanf("%d" , &gg);
        vc[gg].push_back(i + 1);
        vc[i + 1].push_back(gg);
    }
    maxdeep = 0;
    dfs(1 , -1 , 1);
    for(int i = 1 ; i <= n ; i++) {
        if((maxdeep % 2) == (deep[i] % 2)) {
            num[val[i]]-- , ans ^= val[i];
        }
    }//这里处理奇数偶数步用了取巧的方法。就是如果奇偶性和最大深度的奇偶性相同那么就必定是偶数点
    ll count = 0;
    if(ans == 0) {
        ll sum = 0;
        for(int i = 1 ; i <= n ; i++) {
            if((maxdeep % 2) == (deep[i] % 2)) {
                count += num[val[i]];
            }
            else sum++;
        }
        count += (sum * (sum - 1) / 2 + (n - sum) * (n - sum - 1) / 2);
    }
    else {
        for(int i = 1 ; i <= n ; i++) {
            if((maxdeep % 2) == (deep[i] % 2)) {
                count += num[(ans ^ val[i])];
            }
        }
    }
    printf("%lld\n" , count);
    return 0;
}
时间: 2024-10-08 22:17:05

codeforces 812 E. Sagheer and Apple Tree(树+尼姆博弈)的相关文章

Codeforces Round #417 (Div. 2) E. Sagheer and Apple Tree(树上Nim)

题目链接:Codeforces Round #417 (Div. 2) E. Sagheer and Apple Tree 题意: 给你一棵树,每个节点有a[i]个苹果,有两个人要在这个树上玩游戏. 两个人轮流操作,谁不能操作谁就输了. 这个树有一个特性:叶子到根的距离的奇偶性相同. 每次操作可以选一个节点i,和一个数x,x小于当前节点i的苹果数. 对于节点i,如果是叶子节点,就将这x个苹果吃掉. 如果是非叶子节点,就将这x个苹果移向节点i的任意儿子节点. 现在第二个操作的人要交换两个节点的苹果

(博弈\sg) Codeforces Round #417 (Div. 2) E Sagheer and Apple Tree

Sagheer is playing a game with his best friend Soliman. He brought a tree with n nodes numbered from 1 to n and rooted at node 1. The i-th node has ai apples. This tree has a special property: the lengths of all paths from the root to any leaf have t

POJ 3321 Apple Tree (树状数组)

Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 21191   Accepted: 6436 Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been

E - Apple Tree(树状数组+DFS序)

There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been carefully nurturing the big apple tree. The tree has N forks which are connected by branches. Kaka numbers

Codeforces 812E Sagheer and Apple Tree

大致题意: 给你一颗树,这个树有下列特征:每个节点上有若干个苹果,且从根节点到任意叶子节点的路径长度奇偶性相同. 甲和乙玩(闲)游(得)戏(慌). 游戏过程中,甲乙轮流将任意一个节点的若干个苹果移向它的一个叶子节点,若没有叶子节点,那么这些苹果就消失了(被吃掉了). 若一个玩家没法操作,那么算他输. 游戏由甲开始,而乙可以先选择将两个节点上的苹果数交换一下.问乙有多少种交换方式,使得最后乙获胜. Nim游戏: 如果懂Nim游戏的话,就不要看了\(^o^)/~你肯定会这道题了. 懂Nim游戏的定义

Codeforces 812E Sagheer and Apple Tree ——(阶梯博弈)

之前在bc上做过一道类似的阶梯博弈的题目,那题是移动到根,这题是移动到叶子.换汤不换药,只要和终态不同奇偶的那些位置做nim即可.因此这题给出了一个条件:所有叶子深度的奇偶性相同.同时需要注意的是,上次bc中,根节点是不能移动的,因此根节点是终态节点,而这里叶子上面还可以进行操作(可以吃掉),那么就相当于叶子节点都还可以继续向下移动,因此他们不是终态节点,也就是说这题只要和叶子节点同奇偶的做nim即可. 因此,如果nim和已经是0,已经可以满足先手必输了,而题目说了必须要交换,那么只要让奇偶性相

POJ3321 Apple Tree(树状数组)

先做一次dfs求得每个节点为根的子树在树状数组中编号的起始值和结束值,再树状数组做区间查询 与单点更新. #include<cstdio>#include<iostream>#include<cstdlib>#include<cstring>#include<string>#include<algorithm>#include<map>#include<queue>#include<vector>#

POJ 2486 Apple Tree ( 树型DP )

#include <iostream> #include <cstring> #include <deque> using namespace std; #define SIZE 230 #define BACK 1 #define AWAY 0 int DP[SIZE][SIZE][2]; bool visits[SIZE]; int vals[SIZE]; deque< int > tree[SIZE]; int num, steps; void dfs

cf202-div 1-B - Apple Tree:搜索,数论,树的遍历

http://codeforces.com/contest/348/problem/B B. Apple Tree time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output You are given a rooted tree with n vertices. In each leaf vertex there's a single