zoukankan      html  css  js  c++  java
  • HDU_1850_nim游戏

    Being a Good Boy in Spring Festival

    Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 6842    Accepted Submission(s): 4144


    Problem Description
    一年在外 父母时刻牵挂
    春节回家 你能做几天好孩子吗
    寒假里尝试做做下面的事情吧

    陪妈妈逛一次菜场
    悄悄给爸爸买个小礼物
    主动地 强烈地 要求洗一次碗
    某一天早起 给爸妈用心地做回早餐

    如果愿意 你还可以和爸妈说
    咱们玩个小游戏吧 ACM课上学的呢~

    下面是一个二人小游戏:桌子上有M堆扑克牌;每堆牌的数量分别为Ni(i=1…M);两人轮流进行;每走一步可以任意选择一堆并取走其中的任意张牌;桌子上的扑克全部取光,则游戏结束;最后一次取牌的人为胜者。
    现在我们不想研究到底先手为胜还是为负,我只想问大家:
    ——“先手的人如果想赢,第一步有几种选择呢?”
     
    Input
    输入数据包含多个测试用例,每个测试用例占2行,首先一行包含一个整数M(1<M<=100),表示扑克牌的堆数,紧接着一行包含M个整数Ni(1<=Ni<=1000000,i=1…M),分别表示M堆扑克的数量。M为0则表示输入数据的结束。
     
    Output
    如果先手的人能赢,请输出他第一步可行的方案数,否则请输出0,每个实例的输出占一行。
     
    Sample Input
    3
    5 7 9
    0
     
    Sample Output
    1
     

    [定理1]:对于任何一个S态,总能从一堆火柴中取出若干个使之成为T态。

    证明:

        若有n堆火柴,每堆火柴有A(i)根火柴数,那么既然现在处于S态,

        c = A(1) xor A(2) xor … xor A(n) > 0;

      把c表示成二进制,记它的二进制数的最高位为第p位,则必然存在一个A(t),它二进制的第p位也是1。(否则,若所有的A(i)的第p位都是0,这与c的第p位就也为0矛盾)。

        那么我们把x = A(t) xor c,则得到x < A(t).这是因为既然A(t)的第p位与c的第p位同为1,那么x的第p位变为0,而高于p的位并没有改变。所以x < A(t).而

            A(1) xor A(2) xor … xor x xor … xor A(n)

         = A(1) xor A(2) xor … xor A(t) xor c xor … xor A(n)

         = A(1) xor A(2) xor… xor A(n) xor A(1) xor A(2) xor … xor A(n)

       = 0

      这就是说从A(t)堆中取出 A(t) - x 根火柴后状态就会从S态变为T态。证毕

    •对于某个局面(a1,a2,...,an),若a1^a2^...^an==k(k>0)
    •一定存在某个合法的移动,将ai改变成ai'后满足 a1^a2^...^ai'^...^an=0
    •一定存在某个ai,它的二进制表示在k的最高位上是1 (ai^k<ai 成立)
    •将ai改变成ai'=ai^k a1^a2^...^ai'^...^an=a1^a2^...^an^k=0
     有了这个,我们就可以直接找含有最高位为1的值就可以了,但是一定要注意,找到最高位为1后还要判断ai^k<ai,因为有可能有K值的最高位并不是在ai中,譬如k=1,10^K>10.
     
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<stdlib.h>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    int N[105];
    int main()
    {
        int m;
        while(scanf("%d",&m)!=EOF&&m)
        {
            int k=0;
            for(int i=0; i<m; i++)
            {
                scanf("%d",&N[i]);
                k^=N[i];
            }
            if(k==0)
                printf("0
    ");
            else
            {
                int pos=0;
                for(int i=0;i<=30;i++)
                {
                    int tmp=(1<<i);
                    if((tmp&k)>0)
                        pos=i;
                }
                //cout<<pos<<endl;
                int res=0;
                for(int i=0;i<m;i++)
                    if((N[i]&(1<<pos))>0&&(N[i]^k)<N[i])
                        res++;
                printf("%d
    ",res);
            }
        }
        return 0;
    }
  • 相关阅读:
    得物小程序解析data加解密算法
    关于mysql启动报111错误问题的可能性
    我的php笔记(一)
    近期汇编学习@20181125
    近期汇编学习
    《汇编语言》第三章
    《汇编语言》第二章
    《汇编语言》实验一:查看CPU和内存,用机器指令和汇编指令编程
    《汇编语言》第一章
    【8086汇编-Day8】实验九
  • 原文地址:https://www.cnblogs.com/jasonlixuetao/p/5899540.html
Copyright © 2011-2022 走看看