题目描述

定义一种有根二叉树\(T(n)\)如下:

(1)\(T(1)\)是一条长度为\(p\)的链;

(2)\(T(2)\)是一条长度为\(q\)的链;

(3)\(T(i)\)是一棵二叉树,它的左子树是\(T(i-2)\),右子树是\(T(i-1)\)。

现在给定\(p,q,n\),现在Alice和Bob在树\(T(n)\)上玩游戏,每人轮流从树上拿掉一棵子树,直到有一个玩家拿掉根结点所在的子树为止(那么该玩家输了)。现在问先手在第一轮有多少种拿掉子树的方法,可以保证之后自己一定能赢。只用输出答案最后18位即可。

样例:

1 2 5

1 2 10

输出:

1

17

数据范围:保证\(n,p,q \le 2000\)。

解题思路

SG函数的求解

该问题等价于不能拿掉总的根,无法操作者输。关于该问题显然应从SG理论入手。下面推导一般树意义下的SG函数。

引理1:设树\(T\)只有一个儿子,即具有子树\(T_1\),则\(SG(T)=SG(T_1)+1\)。

证明:利用数学归纳法,对树的结点进行归纳。

初始:当\(T\)只有2个结点时,显然成立。

归纳:设\(take(T)\)为\(T\)去掉一棵子树后所有可能的树形态的集合。根据SG基本定理, \[SG(T)=mex(\{T' \in take(T):SG(T')\})\] 利用归纳性质, \[SG(T)=mex(\{0\} \cup \{T' \in take(T_1):SG(T')+1\})=SG(T_1)+1\]

证毕。

引理2:设树\(T\)具有子树\(T_1,\cdots,T_k\),则\(SG(T)=\mathop  \oplus \limits_{1 \le j \le k} (SG({T_j}) + 1)\)。

证明:对于树\(T\)的游戏,显然等价于只有子树\(T_1,\cdots,T_k\)的游戏之和,之间互不影响,因为不到最后一步任何人不会拿掉总的树根。根据引理1即得上式。

根据以上引理,本题中便可得出\(SG[i]=(SG[i-1]+1)\oplus (SG[i-2]+1)\),即可在\(O(n)\)时间复杂度求出原问题中每个\(T(i)(i\le n)\)的SG值。

转化为动态规划问题

如果原问题问谁赢那么就已经做完了。然而现在问的是第一个人第一步有几种能赢的方案,也就是说有几种拿走子树的方案使得之后SG为0。

考虑动态规划。设\(dp[i][j]\)表示在树\(T(i)\)上玩游戏,先手拿走一棵子树后SG值变为\(j-1\)的方案数(这里\(j-1\)是为了后续方便),\(dp[i][0]\)恒定义为1。

初始化:对任意\(1\le j < p\),\(dp[1][j]=1\);对任意\(1\le j < q\),\(dp[2][j]=1\);

转移:对于\(i>2\)的情形,必然从其中一棵子树中选择拿掉一棵子树。以拿掉左子树中的一棵子树为例:此时右子树SG值不变,为了使之后原树SG变为\(j-1\),必须使左子树SG值变为\(((j-1)\oplus (SG[i-1]+1))-1\)。特别地,当\((j-1)\oplus (SG[i-1]+1)\)为0时,表示必须拿掉左子树。这样可得转移方程: \[dp[i][j]=dp[i-2][(j-1)\oplus (SG[i-1]+1)]+dp[i-1][(j-1)\oplus (SG[i-2]+1)]\] 最终答案为\(dp[n][1]\)。这样我们便在状态数的时间复杂度内解决了本问题。

状态数的分析

问题关键在于确定\(dp[i][j]\)中\(j\)到底需要计算到多少。考虑所有\(SG[i](i \le n)\)中二进制位数的最大值(设为\(k\)),那么只需计算\(j < 2^k\)即可。这是因为只要\(j < 2^k\),则转移过程中的\((j+1) \oplus SG[i-1]]\)以及\((j+1) \oplus SG[i-2]\)也必然小于\( 2^k\)。所以现在关键问题在于计算\(SG[i](i \le n)\)中二进制位数的最大值到底是多少。事实上,推导这一问题较为复杂,将留在下一节专门讨论,同时将会得到许多有用的性质。(PS:赛场上我大力猜了一波\(SG[i]<2^{13}=8192\),然后就AC了2333)

关于异或递推式

以下以本题中所用递推式为例(令\(a[i]=SG[i]+1\)变形为\(a[i]=(a[i-1]\oplus a[i-2])+1\)),讨论异或递推式的奇妙性质。

引理3:对任意正整数\(k\),\(a[i] \mod 2^k\)具有循环节。

证明:由于\(a[i] \mod 2^k\)只有有限种取值,故必存在\(x<y\),使得

\[a[x] \equiv a[y] \mod 2^k,a[x+1] \equiv a[y+1] \mod 2^k\]

那么根据递推式必有(对任意\(z>0\))

\[a[x+z] \equiv a[y+z] \mod 2^k\]

另一方面,\(a[i-2]=a[i-1]\oplus (a[i]-1)\),故上式对\(z<0\)也成立。

故\(y-x\)是循环节。证毕。

引理4:\(a[i] \mod 2\)的循环节必为1或3,且循环节为1时数列是有界的。

证明:只需按a[1]和a[2]的值枚举即可:

情况1:001001......循环节为3;

情况2:010010......循环节为3;

情况3:100100......循环节为3;

情况4:1111111......循环节为1,此时递推式中的+1永远不进位,而\(a[4]\)的高位\(=a[3]\)的高位异或\(a[2]\)的高位\(=(a[2]\)的高位异或\(a[1]\)的高位\()\)异或\(a[2]\)的高位\(=a[1]\)的高位,故最终推出\(a[i]=a[i \mod 3]\)。证毕。

定理5:当\(a[i] \mod 2\)的循环节为3时,\(a[i] \mod 2^k\)的循环节为\(3 \times 2^{k-1}\)。

证明:对\(k\)应用数学归纳法,关键在于考虑低\(k-1\)位向高位的进位。设想若低\(k-1\)位不进位,第\(k\)位循环节必然是1或3(类似引理4);只有低位进位才会打乱高位的循环节。

基础:\(k=2\)时,通过枚举\(a[1],a[2]\)模4的余数取值可得所有情况,事实上只有2种:

0232210(进位)23221……循环节为6,中间有1次进位;

00120(进位)30(进位)0(进位)120(进位)3 ……循环节为6,中间有3次进位,且其中两次进位的位置模3余数相同;

归纳:设\(a[x]_k\)表示\(a[x]\)第\(k\)位。考虑在位置\(x\)低\(k-1\)位向第\(k\)位有一次进位。这将导致\(a[x]_k\)取反,进一步导致\(a[x+1]_k\)取反,\(a[x+2]_k\)不变,这种取反是3个一循环的。

直到低\(k-1\)位的下一周期,\(a[x+3 \times 2^{k-2}]_k\)再次被取反从而不变了,之后\(a[x+1+3 \times 2^{k-2}]_k\)也不变……这样一来,\(a[x]\)和\(a[x+3 \times 2^{k-2}]\)第\(k\)位必然不同。进一步地,设\(x \mod 3=i\),则对于所有\(j\),\(a[3j+i]\)和\(a[3j+i+3 \times 2^{k-2}]\)第\(k\)位必然不同。

对于基础里的两种情况,无论是有一次进位,还是有3次进位但两次位置模3余数相同(从而抵消了),均可以保证\(a[3j+i]_k \neq a[3j+i+3 \times 2^{k-2}]_k\)。从而\(a[i] \mod 2^k\)的循环节为\(3 \times 2^{k-1}\)。

接下来再得到第\(k\)位向\(k+1\)位一个循环内的进位情况。由于对于位置\(x\)和\(x+3 \times 2^{k-2}\)低\(k-1\)位向第\(k\)位分别有一次进位,而\(a[x]_k\)和\(a[x+3 \times 2^{k-2}]_k\)又不同,故必有且仅有一次使得低\(k\)位向第\(k+1\)位进位。因此在一个周期\(3 \times 2^{k-1}\)内,一共向第\(k+1\)位的进位次数仍满足基础中的两种情况(进位1次或进位3次但有两次位置模3余数相同)。归纳证毕。

根据证明过程立即可得推论6:

推论6:低\(k\)位在一个周期内最多向第\(k+1\)位进位3次。

定理7:\(a[n]=O(\max(n,p,q))\)。

证明:设\(k\)是最小的满足\(n < 3 \times 2^k\)且\(p,q \le 2^{k+1}\)的正整数。那么在前\(3 \times 2^k\)个数中,低\(k+1\)位最多进位3次。因此\(a[i] < 2^{k+4}\)。

将\(k\)用\(n,p,q\)表达得\(2^k \le \max(p,q,2n/3)\),因此\(a[i] < 16\max(p,q,2n/3)\)。证毕。

定理7表明了本题所使用算法的时间复杂度为\(O(n \times \max(n,p,q))\)。(然而我不清楚出题人是否也是这么证明的(或者并没有证明直接默认了),如果有更简单的方法请务必联系我!)

PS:感谢Emil Jeřábek对以上的证明提供了巨大的帮助!

总结

在SG理论中,通过打表找出SG的规律是一类常见的题型,然而很多时候证明SG的规律是较为困难的。本文以\(a[i]=(a[i-1]\oplus a[i-2])+1\)为例详细推倒了周期性、上界等结论,这种结论实际上是很有一般性的。许多题目中SG函数均存在异或递推式,从而具有类似的周期性。然而应用SG的上界作为状态进行DP的题目则十分具有创新意义,希望以后可以出现更多的以博弈作为桥梁考察异或性质的题目。

AC代码

 1 #include<cstdio>
 2 #include<cstring>
 3 const long long mod = 1e18;
 4 int sg_1[2001];
 5 long long dp[2001][8192];
 6 int main()
 7 {
 8     int n, p, q;
 9     while (scanf("%d%d%d", &p, &q, &n) == 3){
10         sg_1[1] = p; sg_1[2] = q;
11         for (int i = 3; i <= n; i++)
12             sg_1[i] = (sg_1[i - 2] ^ sg_1[i - 1]) + 1;
13         memset(dp[1], 0, sizeof(dp[1]));
14         memset(dp[2], 0, sizeof(dp[2]));
15         for (int i = 0; i < p; i++)
16             dp[1][i] = 1;
17         for (int i = 0; i < q; i++)
18             dp[2][i] = 1;
19         for (int i = 3; i <= n; i++){
20             dp[i][0] = 1;
21             for (int j = 1; j < 8192; j++)
22                 dp[i][j] = (dp[i - 1][(j - 1) ^ sg_1[i - 2]] + dp[i - 2][(j - 1) ^ sg_1[i - 1]]) % mod;
23         }
24         printf("%lld\n", dp[n][1]);
25     }
26 }

转载于:https://www.cnblogs.com/zbh2047/p/9076931.html

一类SG函数递推性质的深入分析——2018ACM陕西邀请赛H题相关推荐

  1. 博弈论SG函数-算法介绍及例题

    一. 基本概念: 1.  Impartial Combinatorial Games(ICG) 公平组合游戏: 1. 两名选手 2. 交替进行某种游戏规定的操作,每操作一次,选手可以在有限的操作(操作 ...

  2. 【组合数学】递推方程 ( 常系数线性非齐次递推方程求解 | 递推方程标准型及通解 | 递推方程通解证明 )

    文章目录 一.递推方程标准型及通解 二.递推方程通解证明 一.递推方程标准型及通解 H(n)−a1H(n−1)−⋯−akH(n−k)=f(n)H(n) - a_1H(n-1) - \cdots - a ...

  3. HDU2018 母牛的故事【递推+记忆化递归】

    母牛的故事 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submiss ...

  4. 递推(一):递推法的基本思想

    所谓递推,是指从已知的初始条件出发,依据某种递推关系,逐次推出所要求的各中间结果及最后结果.其中初始条件或是问题本身已经给定,或是通过对问题的分析与化简后确定. 利用递推算法求问题规模为n的解的基本思 ...

  5. 【组合数学】递推方程 ( 通解定义 | 无重根下递推方程通解结构定理 )

    文章目录 一.通解定义 二.无重根下递推方程通解结构定理 一.通解定义 递推方程解的形式 : 满足 H(n)−a1H(n−1)−a2H(n−2)−⋯−akH(n−k)=0H(n) - a_1H(n-1 ...

  6. hdu 2046 骨牌铺方格 递推求解

    骨牌铺方格 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...

  7. 递推算法与递推套路(手撕算法篇)

    联系我们:有道技术团队助手:ydtech01 / 邮箱:[ydtech@rd.netease.com] 之前学习基础知识的时候也说了,递推和动态规划有这暧昧不清的关系,可以说,动态规划就是多了一个决策 ...

  8. Berlekamp-Massey 算法(求数列的最短递推式)

    用于求数列的最短递推式. 本文参考自 https://www.cnblogs.com/jz-597/p/14983564.html. 增量法,设 RiR_iRi​ 表示第 iii 个历史递推式,当前为 ...

  9. 递推+模拟---想好如何存储?

    递推+模拟 输入输出问题 CCF-CSP考试历年真题题型分类 分组输入--可能有多组测试数据,对于每组数据 递推---从前面已知态--->后续未知态 AcWing 3777. 砖块 AcWing ...

最新文章

  1. Maven学习教程(六)
  2. CocosEditor 1.0Final-IDEA13.0和1.5-IDEA13.1 发布–2014.03.25
  3. Python基础:模块化来搭项目
  4. c# 智能升级程序代码(1)
  5. mysql 主从 通俗易懂_MySQL 主从同步架构中你不知道的“坑”(完结篇)
  6. Dubbo(RPC原理、Dubbo架构负载均衡配置方式)(1)
  7. 用户计算机安全管理,关于加强用户计算机安全管理工作的通知
  8. springBoot事物
  9. 马哥Linux2016最新高薪运维视频课程
  10. 是真的!华为2019年应届博士年薪最高达201万
  11. mysql建帐号数据库出现反斜线_[MySQL FAQ]系列 -- 账号密码包含反斜线时怎么办-阿里云开发者社区...
  12. 深度 linux ansys,deepin安装ansys
  13. proDAD Adobe pr cc2020 会声会影视频转场特效制作软件,滤镜特效插件
  14. BoundsChecker使用
  15. 你还在用二分法求2个鸡蛋100层楼的问题吗?
  16. 通过 Land of Lisp 中的超简短字符游戏例程学习 loop 和 format
  17. 采用开盘价交易的方法
  18. cron表达式入门_Sourcehunt:Cron管理,Hackathon入门,PHP-GUI…
  19. htc 8x android,HTC 8X正式发布 4.3寸屏支持NFC
  20. I.MX6 Linux mipi配置数据合成

热门文章

  1. c# 如何将字符串中用,分开的数字分别存入数组中
  2. 《Code Complete》ch.15 使用条件语句
  3. emca 更改监听端口
  4. linux 下查看log实时输出
  5. TensorFlow – A Collection of Resources
  6. 【MDCC 2015】开源选型之Android三大图片缓存原理、特性对比
  7. 求一颗二叉树中两个节点的最低公共父节点
  8. android中使用DisplayMetrics获取屏幕参数
  9. 联机日志损坏的解决办法
  10. 性能测试知多少--系统计数器与硬件分析