[BZOJ3895]取石子

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3895]取石子相关的知识,希望对你有一定的参考价值。

取石子

题解

在笔者写这篇题解之前,你可以发现,网上大部分流行的解法都是 O ( n ∑ a ) O\\left(n\\sum a\\right) O(na)的,但我们可以发现在 LOJ 的较快代码都是清一色的线性时间复杂度。
这篇题解将主要对这种线性的做法进行讲解。

首先我们抬出我们的结论:
我们记 x = ∑ [ a i = 1 ] x=\\sum [a_i=1] x=[ai=1] 1 1 1堆的个数, y = ∑ [ a i > 1 ] ( a i + 1 ) − 1 y=\\sum [a_i>1](a_i+1)-1 y=[ai>1](ai+1)1,也就是非 1 1 1堆的和。
y ⩽ 2 y\\leqslant 2 y2时,如果 3 ∣ x 3|x 3x,后手必胜,否则先手必胜。
y > 2 y>2 y>2时,如果 2 ∣ x ∧ 2 ∣ y 2|x\\wedge2|y 2x2y,后手必胜,否则先手必胜。

显然,不是 1 1 1的堆是不会对我们的答案产生影响的,它一定会做到最终被减到 0 0 0并且完全合(即自身合并的次数一定被用光)。
事实上,它不可能被任何一个人减到 0 0 0,如果有人妄图将它减到 0 0 0,浪费它的合并次数,那么当他将它从 2 2 2变到 1 1 1,是另一个人就会处于干扰对手的意愿,将其合并到它大于 1 1 1的朋友上,这也可以说明我们 y y y中最后要减去一个没处合并的 1 1 1

显然,如果 y ⩽ 2 y\\leqslant 2 y2,那么我们的序列必然是数个连续的 1 1 1,最后可能跟一个 2 2 2
如果我们的 3 ∣ x 3|x 3x,也就是说我们的 1 1 1的个数是 3 3 3的倍数。
如果我们的先手将一个 1 1 1变为 0 0 0,在有 2 2 2的情况下,后手可以将 2 2 2变成 1 1 1,在没 2 2 2的情况下,后手可以将两个 1 1 1变成 2 2 2
如果先手将一个 2 2 2变成 1 1 1,后手将这个 1 1 1变成 0 0 0即可。
如果先手合并了两个 1 1 1,得到一个 2 2 2,那么在没 2 2 2的情况下,我们可以将一个 1 1 1消去,保持在原状态。
在有 2 2 2的情况,我们考虑现在 x x x的奇偶性没变, y y y的奇偶性变了,显然现在 2 ∤ y 2\\not | y 2y,因为现在它们多了一个可合并项,在 y > 2 y>2 y>2的情况看来,我们的后手现在是胜态。
于是,我们的目的有转到了证明 y > 2 y>2 y>2部分的结论是否成立,不妨先假设 y > 2 y>2 y>2部分的结论时对的,在下面会进行证明,先将 y ⩽ 2 y\\leqslant 2 y2的情况说明完。
如果我们的 3 ∤ x 3\\not | x 3x,那么显然我们的先手可以将现在的情况变为 3 ∣ x 3|x 3x,此时他是后手,可以胜利。
如果 x % 3 = 1 x\\%3=1 x%3=1,直接将这个 1 1 1减掉即可。
如果 x % 3 = 2 x\\%3=2 x%3=2,在有 2 2 2的情况下,可以将 2 2 2变成 1 1 1,没 2 2 2的情况下,将这两个 1 1 1合成 2 2 2
于是我们便达到了 3 ∣ x 3|x 3x的情况,原来的先手现在成了后手,必将胜利。

对于 y > 2 y>2 y>2的情况,我们先说明 2 ∣ x ∧ 2 ∣ y 2|x\\wedge 2|y 2x2y的情况后手是必胜的。
如果先手消一个 1 1 1,后手跟着消 1 1 1即可。
如果先手使 y y y 1 1 1,如果现在 y > 3 y>3 y>3,后手让 y y y 1 1 1即可。否则,如果前面有 1 1 1的话,一定是偶数个,我们合并两个 1 1 1,可以使 y y y变成 6 6 6。不然的话,整个序列中就一个 3 3 3,此时将这个 3 3 3变成 2 2 2,一个 2 2 2明显是后手必胜。
如果先手将一个 1 1 1合并到 2 2 2上,后手跟着合并一个 1 1 1即可。
如果先手将两个 1 1 1合成 2 2 2,此时 y y y会增加 3 3 3,后手使 y y y 1 1 1即可。
这样,无论如何,我们的后手都有能与先手匹敌的方案。
如果 2 ∤ x ∨ 2 ∤ y 2\\not |x\\vee 2\\not |y 2x2y,先手是一定有一种方案使其变成 2 ∣ x ∧ 2 ∣ y 2|x\\wedge 2|y 2x2y的,此时作为后手的原来的先手胜利。
如果 2 ∤ x ∧ 2 ∣ y 2\\not | x\\wedge 2|y 2x2y,先手可以直接消去一个 1 1 1
如果 2 ∣ x ∧ 2 ∤ y 2| x\\wedge 2\\not |y 2x2y,当 y > 3 y>3 y>3时,先手可以将 y y y减去一个 1 1 1,当 y = 3 y=3 y=3时,先手如果前面有 1 1 1就合并连个 1 1 1,否则将 y y y 1 1 1
如果 2 ∤ x ∧ 2 ∤ y 2\\not |x\\wedge 2\\not | y 2x2y,先手可以将一个 1 1 1合并到 2 2 2上面去。
于是,无论如何先手都能赢了。
这样,我们就证罢了 y > 2 y>2 y>2的情况了,那么 y ⩽ 2 y\\leqslant 2 y2的情况也就证明完毕了。

于是,我们直接记录 1 1 1的个数与非 1 1 1的数的总和就可以线性求出答案了。
时间复杂度 O ( n ) O\\left(n\\right) O(n)

源码

这还要看吗。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>

以上是关于[BZOJ3895]取石子的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3895: 取石子[SG函数 搜索]

BZOJ 1874: [BeiJing2009 WinterCamp]取石子游戏 [Nim游戏 SG函数]

BZOJ 1874: [BeiJing2009 WinterCamp]取石子游戏(SG函数)

bzoj1413 [ZJOI2009]取石子游戏

bzoj2000 [Hnoi2010]stone 取石头游戏

bzoj1413: [ZJOI2009]取石子游戏