hdu 2509 Be the Winner 1907 John

12 篇文章 0 订阅

Be the Winner

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1233    Accepted Submission(s): 632


Problem Description
Let's consider m apples divided into n groups. Each group contains no more than 100 apples, arranged in a line. You can take any number of consecutive apples at one time.
For example "@@@" can be turned into "@@" or "@" or "@ @"(two piles). two people get apples one after another and the one who takes the last is 
the loser. Fra wants to know in which situations he can win by playing strategies (that is, no matter what action the rival takes, fra will win).
 

Input
You will be given several cases. Each test case begins with a single number n (1 <= n <= 100), followed by a line with n numbers, the number of apples in each pile. There is a blank line between cases.
 

Output
If a winning strategies can be found, print a single line with "Yes", otherwise print "No".
 

Sample Input
  
  
2 2 2 1 3
 

Sample Output
  
  
No Yes

John

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 1674    Accepted Submission(s): 907

Problem Description
Little John is playing very funny game with his younger brother. There is one big box filled with M&Ms of different colors. At first John has to eat several M&Ms of the same color. Then his opponent has to make a turn. And so on. Please note that each player has to eat at least one M&M during his turn. If John (or his brother) will eat the last M&M from the box he will be considered as a looser and he will have to buy a new candy box. Both of players are using optimal game strategy. John starts first always. You will be given information about M&Ms and your task is to determine a winner of such a beautiful game.
 

Input
The first line of input will contain a single integer T – the number of test cases. Next T pairs of lines will describe tests in a following format. The first line of each test will contain an integer N – the amount of different M&M colors in a box. Next line will contain N integers Ai, separated by spaces – amount of M&Ms of i-th color. Constraints: 1 <= T <= 474, 1 <= N <= 47, 1 <= Ai <= 4747
 

Output
Output T lines each of them containing information about game winner. Print “John” if John will win the game or “Brother” in other case.
 

Sample Input
     
     
2 3 3 5 1 1 1
 

Sample Output
     
     
John Brother


博弈模型:今有若干堆石子,两人依次从中拿取,规定每次只能从一堆中取若干个,
可将一堆全取走,但不可不取,最后取完者为负。

两题算法相同:详细点击 博弈总结
以下为精简版:
  
  

【定义1】:若一堆中仅有一个石子,则被称为孤单堆。若大于1个,则称为充裕堆

【定义2】:T态中,若充裕堆的堆数大于等于2,则称为完全利他态,用T2表示;若充裕堆的堆数等于0,则称为部分利他态。用T0表示。

孤单堆的根数异或智慧影响二进制的最后以为,但充裕堆会影响高位(非最后一位)。一个充裕堆,高位必有一位不为0,则所有根数异或不为0。故不会是T态。

【定理1】:S0态,即仅有奇数个孤单堆,必败。T0态必胜。

证明:S0态,其实就是每次只能取一根。每次第奇数根都由自己取,第偶数根都由对方取,所以最后一根必由自己取。所以必败。同理:T0态必胜。

【定理2】:S1态,只要方法正确,必胜。

证明:若此时孤单堆堆数为奇数,把充裕堆取完;否则,取成一根。这样,就变成奇数个孤单堆,由对方取。由定理1,对方必输,己必胜。

【定理3】:S2态不可转一次变为T0态。

证明:充裕堆数不可能一次由2变为0

【定理4】:S2态可一次转变为T2态。

证明:因为对于任何一个S态,总能从一堆中取出若干个使之成为T态。又因为S1态,只要方法正确,必胜。S2态不可转一次变为T0态,所以转变的T态为T2态。

【定理5】:T2态,只能转变为S2态或S1态。

证明:因为T态,取任何一堆的若干根都将成为S态。由于充裕堆不可能一次由2变为0,所以此时的S态不可能为S0态。得证。

【定理6】:S2态,只要方法正确,必胜。

证明:方法如下:

  1. S2态,就把它变为T2态。(定理4);
  2. 对方只能T2转变为S2态或S1态(定理5)。

    若转变为S2,则转向①。

    若转变为S1,这时己必胜(定理1)。

【定理7】:T2态必输。

证明:同定理6.

综上所述:必输态有:T2S0;必胜态有:S2S1T0

给出结论:先手胜当且仅当 ①所有堆石子数都为1且游戏的SG值为0(即有偶数个孤单堆-每堆只有1个石子数);②存在某堆石子数大于1且游戏的SG值不为0.

证明

  1. 若所有堆都为1SG值为0,则共有偶数堆石子,故先手胜。
  2. i)只有一堆石子数大于1时,我们总可以对该石子操作,使操作后堆数为奇数且所有堆的石子数均为1

    ii)有超过一堆的石子数1时,先手将SG值变为0即可,且总还存在某堆石子数大于1

因为先手胜。

2509AC代码:
#include <iostream>


using namespace std;
int main()
{
int n,a;
    while(cin>>n)
    {
        int flag=0;  //用来标志是否存在充裕堆
        int sum=0;  //SG值
        while(n--)
        {cin>>a;
        if(a>1)
        flag=1;
        sum^=a;
        }
        if((!flag&&sum==0)||(sum!=0&&flag))   //若不存在充裕堆且所有堆石子个数异或结果为0,
                                                //或存在充裕堆且所有堆石子个数异或结果不为0
        cout<<"Yes"<<endl;
        else
        cout<<"No"<<endl;
    }
   return 0;

}

1907AC代码:
#include <iostream>


using namespace std;
int main()
{
    int t,a,n;
    cin>>t;
    while(t--)
    {
        int flag;
        int sum=0;
        cin>>n;
        while(n--)
        {cin>>a;
        if(a>1)
        flag=1;
        sum^=a;
        }
        if((!flag&&sum==0)||(sum!=0&&flag))
        cout<<"John"<<endl;
        else
        cout<<"Brother"<<endl;
    }
    return 0;

}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值