• HDU 5795 A Simple Nim (博弈) ---2016杭电多校联合第六场


    A Simple Nim

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
    Total Submission(s): 79    Accepted Submission(s): 48


    Problem Description
    Two players take turns picking candies from n heaps,the player who picks the last one will win the game.On each turn they can pick any number of candies which come from the same heap(picking no candy is not allowed).To make the game more interesting,players can separate one heap into three smaller heaps(no empty heaps)instead of the picking operation.Please find out which player will win the game if each of them never make mistakes.
     

     

    Input
    Intput contains multiple test cases. The first line is an integer 1T100, the number of test cases. Each case begins with an integer n, indicating the number of the heaps, the next line contains N integers s[0],s[1],....,s[n1], representing heaps with s[0],s[1],...,s[n1] objects respectively.(1n106,1s[i]109)
     

     

    Output
    For each test case,output a line whick contains either"First player wins."or"Second player wins".
     

     

    Sample Input
    2 2 4 4 3 1 2 4
     

     

    Sample Output
    Second player wins. First player wins.
     

     

    Author
    UESTC
     

     

    Source
     

     

    Recommend
    wange2014
    题意:给定n堆石子,每次有两种操作,1是从任意一堆中取任意个,2是把一堆分为三堆且这三堆都不为空,问谁能赢。
    题解:首先看题目的数据范围是1e9,那么算出每个sg肯定会超时,所以我们想到打表找规律。首先我们暴力打表算出200以内的sg函数值,对于一堆石子来说处理出他的所有后继情况。
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    int sg[10005]= {0};
    bool vis[10005];
    int t,cas=1;
    void get()
    {
        memset(sg,0,sizeof(sg));
        sg[0]=0;
        for(int i=1; i<=200; i++)
        {
            memset(vis,0,sizeof(vis));
            for(int j=1;j<=i;j++)
            {
                for(int k=1;j+k<=i;k++)
                {
                    if(j!=0&&k!=0&&((i-j-k)!=0))
                    vis[sg[j]^sg[k]^sg[i-j-k]]=1;//操作1
                }
            }
            for(int j=0;j<i;j++)//操作2
            vis[sg[j]]=1;
            for(int x=0; ; x++)
                if(!vis[x])
                    {
                        sg[i]=x;
                        break;
                    }
        }
    }
    int main()
    {
        get();
        for(int i=1;i<=100;i++)
        printf("i: %d    %d
    ",i,sg[i]);
        return 0;
    }

    运行该代码,我们会得到如下结果:

    注意在这个表当中

    观察结果我们可以得知,当n为8的倍数时,sg(n)=n+1; 当(n+1)为8的倍数时,sg(n)=n-1; 否则sg(n)=n;

    所以我们把sg值异或起来就能判断出谁赢了。

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    using namespace std;
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int n;
            long long x,ans=0;
            scanf("%d",&n);
            for(int i=0;i<n;i++)
            {
                scanf("%lld",&x);
                if(x%8==0)
                ans=ans^(x-1);
                else if((x+1)%8==0)
                ans=ans^(x+1);
                else
                ans=ans^x;
            }
            if(ans)
            puts("First player wins.");
            else
            puts("Second player wins.");
        }
        return 0;
    }
  • 相关阅读:
    和园友们聊聊天
    php编写验证码
    面试题复习记录(二)
    面试题复习记录(一)
    正则表达式学习小记
    javascript学习小记(一)
    大四
    Java小应用程序
    明白这十个故事-->你也就参悟了人生
    Hibernate懒加载深入分析
  • 原文地址:https://www.cnblogs.com/Ritchie/p/5737929.html
Copyright © 2020-2023  润新知