牛客 - 牛牛的树行棋
题目描述
牛牛的树行棋
解法: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. 题目 2. 解题 1. 题目 链接:https://ac.nowcoder.com/acm/contest/10323/A 来源:牛客网 牛牛现在在花园养了n棵树,按顺序从第1棵到第n ...
- 牛客练习赛63 F 牛牛的树行棋 (SG函数+树差分)
链接:https://ac.nowcoder.com/acm/contest/5531/F 来源:牛客网 牛牛的树行棋 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 524288K, ...
- 牛客练习赛63 F.牛牛的树行棋(博弈 SG函数)
题目链接:https://ac.nowcoder.com/acm/contest/5531/F 牛牛的树行棋 前置知识 思路 代码 前置知识 这道题目需要博弈论中的SG函数的知识,这里就不多赘述.主要 ...
- 牛客题霸 [ 树的直径] C++题解/答案
牛客题霸 [ 树的直径] C++题解/答案 题目描述 给定一棵树,求出这棵树的直径,即两个节点距离的最大值. 题解: 不知道大家听没听过一个结论: 树的直径可以通过两边dfs找到 步骤: 1.从任意一 ...
- 牛客网——歪脖子树下的灯
牛客网--歪脖子树下的灯 题目链接:https://ac.nowcoder.com/acm/contest/24803/L 题目来源:牛客网2021年广东工业大学第11届腾讯杯新生程序设计竞赛(同步赛 ...
- [牛客网#35D 树的距离]离散化+线段树合并
[牛客网#35D 树的距离]离散化+线段树合并 分类:Data Structure SegMent Tree Merge 1. 题目链接 [牛客网#35D 树的距离] 2. 题意描述 wyf非常喜欢树 ...
- 牛客 牛牛选物(01背包)
文章目录 1. 题目 2. 解题 1. 题目 链接:https://ac.nowcoder.com/acm/contest/9887/A 来源:牛客网 牛牛有现在有n个物品,每个物品有一个体积v[i] ...
- 牛客 牛牛的独特子序列(双指针/二分查找)
文章目录 1. 题目 2. 解题 2.1 双指针 2.2 二分查找 1. 题目 链接:https://ac.nowcoder.com/acm/contest/9752/B 来源:牛客网 牛牛现在有一个 ...
- 牛客 牛牛爱喝酒(模拟)
文章目录 1. 题目 2. 解题 1. 题目 链接:https://ac.nowcoder.com/acm/contest/9752/A 来源:牛客网 牛牛是一个酒鬼,非常爱喝酒, 一瓶酒m元钱, 两 ...
最新文章
- 华为+长安研发芯片?长安蔚来更名“阿维塔科技”
- 基于Xcode原型驱动的iOS应用设计
- python常见错误-Python错误及异常总结汇总
- 【终极办法】windows下安装完MySQL,为什么cmd不识别命令?
- Halcon例程(基于多个标定图的单目相机标定)详解—— Camera_calibration_multi_image.hdev
- 汇编指令push,mov,call,pop,leave,ret建立与释放栈的过程
- 1650显卡和1050T显卡差距大吗?
- 单片机汉字点阵c语言程序,51单片机C语言多种点阵屏驱动程序(开发软件为keil C...
- java 邮件发送 多人_java 发送邮件(可发送多人,抄送多人,可带附件)
- 万能pdf阅读器卸载
- win10系统steam登陆计算机授权,steam登陆授权
- java 微服务架构图_图解微服务架构演进
- chrome浏览器安装crx Mouse(鼠标手势)插件
- 数字后端概念——MIM cell
- 摄影构图学83年绝版_常用的摄影构图之点线面
- 多传感器融合的四种经典结构
- web字体 衬线字体与非衬线字体区别 字体扫盲
- Python学习笔记(一)三步走安装pip
- 【开始和MySQL做朋友】——初识MySQL
- Open-Falcon学习笔记(一)Open-Falcon v0.3.0环境搭建