\(\mathcal{Decription}\)

  Link.

  定义一棵圣诞树:

  • 是仙人掌。

  • 不存在两个同一环上的点,度数均 \(\ge 3\)。

  给出 \(n\) 棵互不相关的圣诞树,双人博弈,每轮切断一棵圣诞树的一条边,并且与该树根不向连的部分全部消失,不能操作者负。求先手是否有必胜策略。

  多测,\(T,n\le 100\),\(m\le 500\)。

\(\mathcal{Solution}\)

  没有什么不说人话的定理和结论,这里只应用 SG 函数和 Nim 游戏的基础知识。

  本题解中,定义树上“长度”为两点间边的数量。

  首先,考虑从根连出多条链的图,显然是 Nim 游戏,每堆石子就是链的长度,根的 SG 函数为这些长度的异或和。


  接下来考虑任意一棵树,发现上述结论可以归纳地推广。根据定义,全局 SG 函数为各部分独立 SG 函数异或和,得到:

\[ \operatorname{sg} (u)=\bigoplus_{v\in son_u} (\operatorname{sg} (v)+1)
\]

  注意这里 \(\operatorname{sg} (u)\) 实际上表示 \(u\) 子树的 SG 函数值。其中 \(+1\) 意为每堆石子(链)的长度都 \(+1\)。


  回忆一下 SG 函数的定义:

\[ \operatorname{sg} (S)=\operatorname{mex}_{T\in\operatorname{next}(S) }\{\operatorname{sg} (T)\}\tag{*}
\]

  此后,考虑从 \((*)\) 式的角度求环的 SG 函数。环的后继状态为删除环上任意一条边得到两条链,而链是 Nim 游戏,SG 函数为链长异或和,可以解决。形式地,设环 \(C\) 的大小为 \(n\),有:

\[ \operatorname{sg} (C)=\operatorname{mex}_{a+b=n-1\land(a,b\in\mathbb N)}\{a\oplus b\}
\]

  分 \(n\) 的奇偶性讨论:

  1. \(2|n \Rightarrow 2\not|(n-1)\),而 \(a+b=n-1\),所以 \(a,b\) 奇偶性不同,则它们二进制最低位不同。那么两数异或值不可能为 \(0\),即集合中不存在 \(0\),那么此时 \(\operatorname{sg} (C)=0\)。

  2. \(2\not|n \Rightarrow 2|(n-1)\),而 \(a+b=n-1\),同理地,两数异或值必然为偶数,而且显然存在 \(0\)。得到 \(\operatorname{sg} (C)=1\)。

  综上,\(\operatorname{sg} (C)=[2\not|n]\)。


  回到本题,“圣诞树”的定义保证了环在缩点后的图中是叶子,所以对于环,用环的 SG 函数算,否则用树的 SG 函数算,最后求每棵圣诞树的 SG 异或就能判断先手胜负啦。

  单棵树复杂度 \(\mathcal O(n)\)。

\(\mathcal{Code}\)

/* Clearink */

#include <cstdio>

const int MAXN = 100, MAXM = 500;
int n, m, ecnt, head[MAXN + 5], dep[MAXN + 5], sg[MAXN + 5];
bool vis[MAXN + 5]; struct Edge { int to, nxt; } graph[MAXM * 2 + 5]; inline void link ( const int s, const int t ) {
graph[++ ecnt] = { t, head[s] };
head[s] = ecnt;
} inline int calcSG ( const int u, const int fe ) {
/*
返回值表示当前找到的环的顶点(唯一可能度数 >= 3 的点),若不在环上,返回 0。
*/
vis[u] = true;
for ( int i = head[u], v, cir; i; i = graph[i].nxt ) {
if ( ( i ^ 1 ) == fe || !( v = graph[i].to ) ) continue;
if ( vis[v] ) {
sg[v] ^= ( dep[u] - dep[v] + 1 ) & 1;
graph[i ^ 1].to = 0;
return v;
}
dep[v] = dep[u] + 1, cir = calcSG ( v, i );
if ( !cir ) sg[u] ^= sg[v] + 1;
else if ( cir ^ u ) return cir;
}
return 0;
} inline void clear () {
ecnt = 1;
for ( int i = 1; i <= n; ++ i ) head[i] = sg[i] = dep[i] = vis[i] = 0;
} int main () {
for ( int T; ~scanf ( "%d", &T ); ) {
int ans = 0;
while ( T -- ) {
clear ();
scanf ( "%d %d", &n, &m );
for ( int i = 1, u, v; i <= m; ++ i ) {
scanf ( "%d %d", &u, &v );
link ( u, v ), link ( v, u );
}
calcSG ( 1, 0 ), ans ^= sg[1];
}
puts ( ans ? "Sally" : "Harry" );
}
return 0;
}

Solution -「POJ 3710」Christmas Game的更多相关文章

  1. 「POJ 3666」Making the Grade 题解(两种做法)

    0前言 感谢yxy童鞋的dp及暴力做法! 1 算法标签 优先队列.dp动态规划+滚动数组优化 2 题目难度 提高/提高+ CF rating:2300 3 题面 「POJ 3666」Making th ...

  2. Solution -「ARC 104E」Random LIS

    \(\mathcal{Description}\)   Link.   给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...

  3. Solution -「ACM-ICPC BJ 2002」「POJ 1322」Chocolate

    \(\mathcal{Description}\)   Link.   \(c\) 种口味的的巧克力,每种个数无限.每次取出一个,取 \(n\) 次,求恰有 \(m\) 个口味出现奇数次的概率. \( ...

  4. 「POJ Challenge」生日礼物

    Tag 堆,贪心,链表 Solution 把连续的符号相同的数缩成一个数,去掉两端的非正数,得到一个正负交替的序列,把该序列中所有数的绝对值扔进堆中,用所有正数的和减去一个最小值,这个最小值的求法与「 ...

  5. Solution -「CTS 2019」「洛谷 P5404」氪金手游

    \(\mathcal{Description}\)   Link.   有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ...

  6. Solution -「BZOJ 3812」主旋律

    \(\mathcal{Description}\)   Link.   给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...

  7. Solution -「CF 1342E」Placing Rooks

    \(\mathcal{Description}\)   Link.   在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ...

  8. 「POJ 3268」Silver Cow Party

    更好的阅读体验 Portal Portal1: POJ Portal2: Luogu Description One cow from each of N farms \((1 \le N \le 1 ...

  9. Solution -「简单 DP」zxy 讲课记实

    魔法题位面级乱杀. 「JOISC 2020 Day4」治疗计划 因为是不太聪明的 Joker,我就从头开始理思路了.中途也会说一些和 DP 算法本身有关的杂谈,给自己的冗长题解找借口. 首先,治疗方案 ...

随机推荐

  1. Leetcode系列之两数之和

    Leetcode系列之两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标.你可以假设每种输入只会对应一个答案.但是,你 ...

  2. 【Warrior刷题笔记】剑指offer 32. 三道题,让你学会二叉树的深度广度优先遍历与递归迭代技术

    题目一 剑指 Offer 32 - I. 从上到下打印二叉树 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/cong-shang-dao-xi ...

  3. 【Java】==与equals

    ==与equals 一. == 可以使用在基本数据类型变量和引用数据类型变量中 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等.(不一定类型要相同) 如果比较的是引用数据类型变量:比较两 ...

  4. Go语言测试:testing

    学习参考来源:https://www.liwenzhou.com/posts/Go/16_test/ go test工具 必须导入包: import "testing" go te ...

  5. Maven 框架结构知识总结

    1.maven目录结构 目录 内容 ${basedir} 存放pom.xml和所有子目录 ${basedir}/src/main/java 项目Java代码 ${basedir}/src/main/r ...

  6. vue学习6-if判断

        <p v-if="weather=='sun'">去公园</p>     <p v-else-if="weather=='s'&qu ...

  7. ajax的核心

    <script> // ajax 简称(a 代表异步 j 代表javascript a 代表 and x 代表xml--是一种带有标签的数据格式,被json取代了) //ajax 是异步对 ...

  8. vector自实现(一)

    vector.h: #ifndef __Vector__H__ #define __Vector__H__ typedef int Rank; #define DEFAULT_CAPACITY 3 t ...

  9. Python小练习-购物商城(一部分代码,基于python2.7.5)

    新手写作,用来练习与提高python编写.思考能力,有错误的地方请指正,谢谢! 第一次写博客,课题是一位大神的博客,本着练习的目的,就自己重写了一遍,有很多不足的地方,希望借博客记录下自己的成长:  ...

  10. JavaScript如何实现上拉加载,下拉刷新?

    转载地址: 面试官:JavaScript如何实现上拉加载,下拉刷新? 一.前言 下拉刷新和上拉加载这两种交互方式通常出现在移动端中 本质上等同于PC网页中的分页,只是交互形式不同 开源社区也有很多优秀 ...