题目
思路
在正常情况下,需要进行 ( n − 1 ) (n-1) (n−1) 次合并和 ∑ a \sum a ∑a 次取石子。那么这个数的奇偶性很可能就是答案。
仅剩的问题是,如果一堆石子是被取完的,那么合并次数就变少了。
简单思考一下就会发现,在 a i ⩾ 2 a_i\geqslant 2 ai⩾2 时,不会出现这样的情况。将对手操作过的石子堆立刻与别的石子堆合并,就可以始终使得 a i ⩾ 2 a_i\geqslant 2 ai⩾2 。
那么 a i = 1 a_i=1 ai=1 的石子堆(下文称为 “单石子”)该怎么处理呢?一般来说,可以考虑对称操作消除影响;然而本题中,合并操作是无法对称的!
我又考虑,去掉单石子(下文称为 “外面”)是先手必胜 o r or or 后手必胜时,有奇数 o r or or 偶数个单石子的情况。多数情况下 这是正确的;然而在本题中,这种分类方法太粗糙了!
不得已,只能手玩找规律。我手玩了单石子数目不超过 6 6 6 的所有情况,仍然没有发现任何规律;但是我突然想到——利用程序打表!于是我就把表打了出来,发现单石子数目对结果的影响是有循环节 6 6 6 的!
于是这题就做出来了。虽然没有任何道理。想有道理也可以,归纳法呗。
我的手玩过程附在文末。这个过程启示我,只有四种情况:外面为空;外面只有一堆 a = 2 a=2 a=2 的石子;外面是先手必胜;外面是先手必败。
于是把四个情况的胜负性都存下来,就可以打表了。本来应当存在一个问题是,外面是先手必胜,操作后得到先手必败;外面是先手必败,操作后得到先手必胜;这是一个循环调用。但是我的手玩过程告诉我:应当不存在此种情况。
代码
#include <cstdio> // Dangerous Dark Ghost!!!
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
typedef long long llong;
inline int readint(){
int a = 0, c = getchar(), f = 1;
for(; !isdigit(c); c=getchar())
if(c == '-') f = -f;
for(; isdigit(c); c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
void writeint(unsigned x){
if(x > 9) writeint(x/10);
putchar(char((x%10)^48));
}
const int MAXN = 1005;
/// empty, only a = 2, win, lose
int e[MAXN], a2[MAXN], w[MAXN], l[MAXN];
int main(){
e[0] = 0, a2[0] = 0, w[0] = 1, l[0] = 0;
e[1] = a2[1] = w[1] = l[1] = 1;
e[2] = 1; // just meld
for(int i=2; i<=5; ++i){
e[i+1] = !(a2[i-1] && e[i]);
a2[i] = !(e[i+1] && a2[i-1] && w[i-1] && w[i-2]);
w[i] = !(l[i-1] && w[i-1] && l[i-2]); // and l[i]
l[i] = !(w[i] && w[i-1] && l[i-1] && w[i-2]);
// printf("%d %d %d %d\n",e[i],a2[i],w[i],l[i]);
}
for(int T=readint(),ans; T; --T){
int n = readint();
int sum = -1, cnt = 0;
for(int i=1,a; i<=n; ++i){
a = readint();
if(a == 1) ++ cnt;
else sum += a+1;
}
if(cnt == n-1 && sum == 2) ans = a2[cnt%6];
else if(cnt == n) ans = e[cnt%6];
else if(sum&1) ans = w[cnt%6];
else ans = l[cnt%6];
puts(ans ? "YES" : "NO");
}
return 0;
}
同理 “外面” 是后手必胜,而 a i = 1 a_i=1 ai=1 的石子有奇数堆时,是先手必胜。
“外面” 是先手必胜呢?考虑 a i = 1 a_i=1 ai=1 的石子有奇数堆。可以用上面的对抗性策略,使得 first player \text{first player} first player 拿走最后一个 a i = 1 a_i=1 ai=1,然后 second player \text{second player} second player 就赢了。
后记
查了一下,网上还有 O ( n ∑ a ) \mathcal O(n\sum a) O(n∑a) 的递推方法:用 f i , j f_{i,j} fi,j 表示 i i i 个单石子、外面需要进行 j j j 次操作时的胜负性。但是我有点疑惑……为啥外面的石子不能变成单石子呢?为啥外面的石子一定要完全合并呢?我不太懂。
手玩过程
一个单石子
先手必胜。如果外面是先手必胜,你就把单石子合并过去,得到先手必败;如果外面先手必败,直接将单石子拿走。
将单石子合并到外面 a n d and and 将其直接拿走,两种方案的胜负性不同。选择先手必败的即可。故 first player \text{first player} first player 必胜。
两个单石子
- 如果外面是空的,先手选择合并单石子,然后 first player \text{first player} first player 必胜。
- 外面是先手必胜,先手选择合并单石子,得到
零个单石子
の 后手必胜局面,则 first player \text{first player} first player 必胜。 - 外面是后手必胜(非空),则先手不能合并单石子、不能造出
一个单石子
,只能在外面操作。如果外面满足 a i > 2 a_i>2 ai>2,在外面操作后,变成 ( 2 ) (2) (2) 中情况, second player \text{second player} second player 赢了。 - 如果外面存在 a i = 2 a_i=2 ai=2,那么操作它试试!后手肯定会考虑将 a i ′ = 1 a'_i=1 ai′=1 立即合并走。如果外面有至少两堆,那么合并走之后就会得到 a j ′ ⩾ 3 a_j'\geqslant 3 aj′⩾3,则 second player \text{second player} second player 赢了。
- 如果外面仅有一堆
a
i
=
2
a_i=2
ai=2,操作之后变为
三个单石子
の 外面为空,这是先手必败的。所以 first player \text{first player} first player 必胜了!
总结:外面空则胜;外面仅 a i = 2 a_i=2 ai=2 则胜;否则与外面胜负情况相同。
三个单石子
- 外面为空,合并会得到
一个单石子
,拿走就变为两个单石子
の 外面为空,所以 second player \text{second player} second player 必胜。 - 外面非空,类比
一个单石子
,要么合并一个单石子到外面,要么直接拿走,构造出两个单石子
の 外面非空。除去 ( 3 ) (3) (3) 中的特例,都是 first player \text{first player} first player 必胜。 - 特例是,外面仅有一个
a
i
=
2
a_i=2
ai=2,此时上述两种方案都行不通。若将
a
i
=
2
a_i=2
ai=2 拿走一颗,变为
四个单石子
の 外面为空,这还是先手必胜。若合并两个单石子,则变为一个单石子
,更不行。故此时 second player \text{second player} second player 必胜了。
总结:外面空则败;外面仅 a i = 2 a_i=2 ai=2 则败;否则必胜。
四个单石子
- 外面为空,则
first player
\text{first player}
first player 胜。因为拿走一个就得到
三个单石子
の 外面为空。 - 外面是先手必胜,则先手合并单石子,得到
两个单石子
の 外面后手必胜(非空,非仅 a i = 2 a_i=2 ai=2 这堆),所以 first player \text{first player} first player 胜。 - 外面是后手必胜(非空),则先手不能合并单石子、一般不敢造出
三个单石子
,只能在外面操作。如果外面满足 a i > 2 a_i>2 ai>2,显然 second player \text{second player} second player 必胜。 - 如果外面存在
a
i
=
2
a_i=2
ai=2,类比
两个单石子
,也没啥用。当外面仅有一个 a i = 2 a_i=2 ai=2 时,造出三个单石子
first player \text{first player} first player 就必胜了。
总结:外面空则胜;外面仅 a i = 2 a_i=2 ai=2 则胜;否则与外面胜负情况相同。
五个单石子
- 外面为空,则
first player
\text{first player}
first player 必胜了!因为合并后得到
三个单石子
の 外面仅 a i = 2 a_i=2 ai=2 。 - 外面非空,很可能
first player
\text{first player}
first player 必胜,原因跟
三个单石子
相同。特例见 ( 3 ) (3) (3) 。 - 特例是,外面仅有一个
a
i
=
2
a_i=2
ai=2 。变为
六个单石子
の 外面为空,则 first player \text{first player} first player 胜。
总结:必胜。跟 一个单石子
一样霸气。
六个单石子
- 外面为空,可以发现这是 second player \text{second player} second player 必胜的。
- 外面先手必胜,可以发现这是 first player \text{first player} first player 必胜的。
- 外面后手必胜(非空),一般情况下是 second player \text{second player} second player 必胜。
- 如果外面仅有一个 a i = 2 a_i=2 ai=2,还是 second player \text{second player} second player 必胜啊。
总结:外面空则败;否则与外面胜负情况相同。
七个单石子
- 外面为空,变为
六个单石子
の 外面为空,故 first player \text{first player} first player 必胜。 - ……(作者已经讨论到断气了)