洛谷 P4279 [SHOI2008]小约翰的游戏 解题报告

P4279 [SHOI2008]小约翰的游戏

题目描述

小约翰经常和他的哥哥玩一个非常有趣的游戏:桌子上有(n)堆石子,小约翰和他的哥哥轮流取石子,每个人取的时候,可以随意选择一堆石子,在这堆石子中取走任意多的石子,但不能一粒石子也不取,我们规定取到最后一粒石子的人算输。 小约翰相当固执,他坚持认为先取的人有很大的优势,所以他总是先取石子,而他的哥哥就聪明多了,他从来没有在游戏中犯过错误。小约翰一怒之前请你来做他的参谋。自然,你应该先写一个程序,预测一下谁将获得游戏的胜利。

输入输出格式

输入格式:

本题的输入由多组数据组成,第一行包括一个整数(T),表示输入总共有(T)组数据((T≤500))。 每组数据的第一行包括一个整数(N)(N≤50)),表示共有(N)堆石子,接下来有(N)个不超过(5000)的整数,分别表示每堆石子的数目。

输出格式:

每组数据的输出占一行,每行输出一个单词。如果约翰能赢得比赛,则输出“John”,否则输出“Brother”,请注意单词的大小写。

说明

对于(40\%)的数据,(T ≤ 250)。 对于(100\%)的数据,(T ≤ 500)


( t{Anti-SG})

必胜条件

  1. 游戏(SG ot=0),子游戏存在(SG>1)
  2. 游戏(SG=0),子游戏不存在(SG>1)

情况2显然,因为最后一个是奇数堆就输了。

情况1可以从普通(NIM)的角度思考。

发现只有一个子游戏的(SG)函数大于(1)时可以转到必胜态,往这个状态靠拢就行了。

正经证明不会


Code:

#include <cstdio>
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,mx=0,SG=0;
        scanf("%d",&n);
        for(int x,i=1;i<=n;i++)
            scanf("%d",&x),mx=mx>x?mx:x,SG^=x;
        if(mx==1) puts(SG?"Brother":"John");
        else puts(SG?"John":"Brother");
    }
    return 0;
}

2018.12.18

原文地址:https://www.cnblogs.com/butterflydew/p/10137423.html