题目描述

牛牛的树行棋

解法:SG函数+DFS(C++)

详细参考 Lskkkno1的解 和 段三园的小迷弟的解

我们先介绍关于 SG 函数的两个结论:

  • 当前局面的 SG 值为 0,先手必败,否则先手必胜
  • 若一个游戏是多个独立游戏组成的,那么当前局面的 SG 值是多个独立游戏 SG 值的异或值

那么,对这道题而言,每一枚棋子其实都是独立的,也就是说,当前局面的多个独立游戏就是每一枚棋子,当前局面的 SG 值就是每一枚棋子的 SG 值的异或和。

那么一枚棋子的 SG 值怎么求呢?

若一枚棋子在叶子节点(后继状态是空集),它的 SG 值为 0

若一枚棋子的后继节点只有叶子节点,它的 SG 值为 1

若一枚棋子的后继节点 SG 值最大为 1 (那么肯定也有 0),它的 SG 值为 2

若一枚棋子的后继节点 SG 值最大为 2 (那么肯定也有 1, 0),它的 SG 值为 3

⋯ ⋯ \cdots \cdots ⋯⋯

就是说,除叶节点外,每个节点的 SG 值等于 m a x ( 子 树 的 S G 值 ) + 1 max(子树的 SG 值) + 1 max(子树的SG值)+1

根据上面的结论,求出所有 SG 值的异或和 x x o r xxor xxor,如果 x x o r ! = 0 xxor != 0 xxor!=0,先手有必赢策略,否则必输

那么知道必赢之后该怎么求解方法数呢?

因为 SG 值为 0 的局面是必输的,也就是说,我们需要在第一次移动之后使得局面的 SG 值一定要等于 0

考虑当前要移动的棋子为 i i i,它的 SG 值为 S G i SG_i SGi​,且令移动之前局面的 SG 值为 x x o r xxor xxor,要使移动后总的 SG 值为 0,这枚棋子需要移动到 SG 值等于 S G i ⊕ x x o r SG_i \oplus xxor SGi​⊕xxor 的位置

于是,我们通过一个计数数组 c n t [ . . . ] cnt[...] cnt[...],记录当前根节点下的全部子节点出现的 SG 值的次数,然后求和 c n t [ S G i ⊕ x x o r ] cnt[SG_i \oplus xxor] cnt[SGi​⊕xxor] 就是我们想要的结果啦

当然,cnt[sg[x]]++; cnt[sg[x]]--; 是为了保证 DFS 到达叶节点回溯时走过的路已经计算完毕,如果不减掉那就会重复计算

#include <bits/stdc++.h>using namespace std;const int N = 5e5+10;
vector<int> e[N];
int n, u, v, sum, xxor, sg[N<<1], cnt[N<<1];void dfs1(int x, int pre){// 计算每个节点的 sg 值,判断先手是否能赢for(auto i: e[x]){if(i!=pre){dfs1(i, x);sg[x] = max(sg[x], sg[i]+1);}}xxor ^= sg[x];
}void dfs2(int x, int pre){// 求必赢策略中的第一步的方法数cnt[sg[x]]++;sum += cnt[sg[x]^xxor];for(auto i: e[x])if(i!=pre) dfs2(i, x);cnt[sg[x]]--;
}int main()
{cin >> n;for(int i=1;i<n;i++){cin >> u >> v;e[u].push_back(v);e[v].push_back(u);}dfs1(1, -1);if(xxor){dfs2(1, -1);cout << "YES" << endl;cout << sum << endl;}else cout << "NO" << endl;return 0;
}

牛客 - 牛牛的树行棋相关推荐

  1. 牛客 牛牛浇树(差分)

    文章目录 1. 题目 2. 解题 1. 题目 链接:https://ac.nowcoder.com/acm/contest/10323/A 来源:牛客网 牛牛现在在花园养了n棵树,按顺序从第1棵到第n ...

  2. 牛客练习赛63 F 牛牛的树行棋 (SG函数+树差分)

    链接:https://ac.nowcoder.com/acm/contest/5531/F 来源:牛客网 牛牛的树行棋 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 524288K, ...

  3. 牛客练习赛63 F.牛牛的树行棋(博弈 SG函数)

    题目链接:https://ac.nowcoder.com/acm/contest/5531/F 牛牛的树行棋 前置知识 思路 代码 前置知识 这道题目需要博弈论中的SG函数的知识,这里就不多赘述.主要 ...

  4. 牛客题霸 [ 树的直径] C++题解/答案

    牛客题霸 [ 树的直径] C++题解/答案 题目描述 给定一棵树,求出这棵树的直径,即两个节点距离的最大值. 题解: 不知道大家听没听过一个结论: 树的直径可以通过两边dfs找到 步骤: 1.从任意一 ...

  5. 牛客网——歪脖子树下的灯

    牛客网--歪脖子树下的灯 题目链接:https://ac.nowcoder.com/acm/contest/24803/L 题目来源:牛客网2021年广东工业大学第11届腾讯杯新生程序设计竞赛(同步赛 ...

  6. [牛客网#35D 树的距离]离散化+线段树合并

    [牛客网#35D 树的距离]离散化+线段树合并 分类:Data Structure SegMent Tree Merge 1. 题目链接 [牛客网#35D 树的距离] 2. 题意描述 wyf非常喜欢树 ...

  7. 牛客 牛牛选物(01背包)

    文章目录 1. 题目 2. 解题 1. 题目 链接:https://ac.nowcoder.com/acm/contest/9887/A 来源:牛客网 牛牛有现在有n个物品,每个物品有一个体积v[i] ...

  8. 牛客 牛牛的独特子序列(双指针/二分查找)

    文章目录 1. 题目 2. 解题 2.1 双指针 2.2 二分查找 1. 题目 链接:https://ac.nowcoder.com/acm/contest/9752/B 来源:牛客网 牛牛现在有一个 ...

  9. 牛客 牛牛爱喝酒(模拟)

    文章目录 1. 题目 2. 解题 1. 题目 链接:https://ac.nowcoder.com/acm/contest/9752/A 来源:牛客网 牛牛是一个酒鬼,非常爱喝酒, 一瓶酒m元钱, 两 ...

最新文章

  1. 华为+长安研发芯片?长安蔚来更名“阿维塔科技”
  2. 基于Xcode原型驱动的iOS应用设计
  3. python常见错误-Python错误及异常总结汇总
  4. 【终极办法】windows下安装完MySQL,为什么cmd不识别命令?
  5. Halcon例程(基于多个标定图的单目相机标定)详解—— Camera_calibration_multi_image.hdev
  6. 汇编指令push,mov,call,pop,leave,ret建立与释放栈的过程
  7. 1650显卡和1050T显卡差距大吗?
  8. 单片机汉字点阵c语言程序,51单片机C语言多种点阵屏驱动程序(开发软件为keil C...
  9. java 邮件发送 多人_java 发送邮件(可发送多人,抄送多人,可带附件)
  10. 万能pdf阅读器卸载
  11. win10系统steam登陆计算机授权,steam登陆授权
  12. java 微服务架构图_图解微服务架构演进
  13. chrome浏览器安装crx Mouse(鼠标手势)插件
  14. 数字后端概念——MIM cell
  15. 摄影构图学83年绝版_常用的摄影构图之点线面
  16. 多传感器融合的四种经典结构
  17. web字体 衬线字体与非衬线字体区别 字体扫盲
  18. Python学习笔记(一)三步走安装pip
  19. 【开始和MySQL做朋友】——初识MySQL
  20. Open-Falcon学习笔记(一)Open-Falcon v0.3.0环境搭建

热门文章

  1. linux 版本号 笔记本_怎样选购用于Linux的笔记本电脑?
  2. Robot Framework 环境搭建步骤 RIDE保存时提示没有权限 RIDE使用时候常用问题(在最后)
  3. 易语言制作大漠模块API进程ID取窗口句柄
  4. 咏码畜(邀月于辛卯年四月十六日)
  5. GBase 8a集群之智能索引
  6. okhttp3使用总结
  7. LRUCache详解
  8. 奥黛丽.赫本的美丽之本
  9. XZ_iOS之将图片保存到手机导致崩溃的问题
  10. Android插件化探索与发现