1. 程式人生 > >【bzoj1022】小約翰的遊戲John

【bzoj1022】小約翰的遊戲John

https tps problem names href else ace other --

Portal -->bzoj1022

Solution

?  ?這題其實是裸的反Nim,這裏主要是為了寫反Nim遊戲的證明

?  ?首先給出反Nim(anti-nim)的定義和結論:

【定義】桌子上有 N 堆石子,遊戲者輪流取石子; 每次只能從一堆中取出任意數目的石子,但不能不取;取走最後一個石子者敗

【結論】先手必勝當且僅當滿足下面兩個條件中的一個

?  ?(1)所有堆的石子數都為\(1\)且遊戲的\(sg\)值為\(0\)

?  ?(2)有些堆的石子數大於\(1\)且遊戲的\(sg\)值不為\(0\)

? ?  ?

?  ?然後我們來證明anti-nim遊戲的結論,可以分成兩種情況討論(以下內容摘自論文):

1、每堆只有\(1\)個石子:

?  ?那麽顯然先手必勝當且僅當石子堆數\(n\)為偶數

2、其他情況:

??  ?(1)當遊戲的\(sg\)值不為\(0\)時:若還有至少兩堆石子的數目大於$ 1$,則先手將 \(sg\)值變為 $0 \(即可;若只有一堆石子數大於\) 1$,則先手總可以將狀態變為有奇數個\(1\)(可以把大於\(1\)的那堆直接取完或者取剩\(1\)個),所以,當\(sg\)不為\(0\)時先手必勝

??  ?(2)當遊戲的\(sg\)值為\(0\)時:至少有兩堆石子的數目大於 \(1\),則先手決策完之後,必定至少有一堆的石子數大於 \(1\),且\(sg\)值(當前遊戲局面的)不為\(0\)

,由上段的論證我們可以發現,此時,無論先手如何決策,都只會將遊戲帶入先手必勝局,所以先手必敗

?  ?

?  ?代碼大概長這個樣子

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,T,ans,cnt;

int main(){
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
#endif
    int x;
    scanf("%d",&T);
    for (int o=1;o<=T;++o){
        ans=0; cnt=0;
        scanf("%d",&n);
        for (int i=1;i<=n;++i){
            scanf("%d",&x),ans^=x;
            if (x>1) ++cnt;
        }
        if (cnt==0) printf(n%2?"Brother\n":"John\n");
        else printf(ans?"John\n":"Brother\n");
    }
}

【bzoj1022】小約翰的遊戲John