Split Game (SG函数)单堆分为多堆

版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/89376291

题目:oj26548

Description

For a long time, rich clientele of Binary Casino has been requesting a new way to gamble their money. To fulfill their wishes, the director of Binary Casino decided to introduce a new game called Split Your Tokens.

This game is played only when a customer is about to exit the casino. Instead of exchanging tokens won during his visit, he may take up casino's challenge and bet all of his earned tokens on winning this game. Should the customer lose, all of his tokens are lost in favor of the casino.

When the game starts, the customer splits his tokens into N piles with not necessarily same amount of tokens in each pile. The customer and the casino then exchange turns – in this game we denote the customer as the first player and the casino as the second player. Each player in his turn decides which pile he wants to split and chooses a positive integer K which is smaller than the size of the selected pile. Then the player splits the selected pile into as many piles of size K as possible. If any tokens remain, they form another pile on their own. A player loses the game when he can not do any more splitting. The customer (first player) always plays first.

The director of Binary Casino is however not sure, whether this game will be profitable for the casino in the long term. Your task is thus to determine, for a given configuration of piles, which player wins when both players play optimally.

Input

The first line contains one integer N (1 ≤ N ≤ 2000), the number of piles. The second line contains a sequence of N integers Pi (1 ≤ Pi ≤ 2000), Pi represents the number of tokens in the i-th pile.

Output

Output a single line with either "First" or "Second", depending on which player wins the game if both play optimally.

Sample Input

Sample #1

3
1 2 3

Sample #2

3
1 2 2

Sample Output

Sample #1

First

Sample #2

Second

Source

CTU Open 2018

题意:有n个堆,每个堆的高度为pi,两人玩游戏,每次可以任选一堆,并选择小于等于此堆的高度h(h<=pi)把这堆分离成高度为h的堆和高度为pi%h的堆。堆高为1时,是不可再分的。问:先手win还是后手win?

题解:

SG函数,我们先预处理前2000的SG函数。你可以先看下代码,这里每次求SG值时,后继状态(一个堆分为多个堆)我们是异或的,不像之前的(一个堆就分为一个堆)就 直接标记下后继状态。为什么呢?

1,每个SG函数其实就是代表了是否为必胜态或者必败态

2,一个堆分为2个堆 ,此时的后继状态应为它们的异或值,为什么呢?SG函数它本身就是多个堆异或,异或为0为必败态,反之为必胜态。那么我们可以这样想,一个堆分为两个堆,若异或为0,则这分离出来的两个堆就是必败态。

代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn=5e5+10;

typedef long long LL;

const LL mod=1e9+7;

int SG[2010];
set<int> S;

void init()
{

    SG[1]=0;///初始化,高度为1的堆为必败态,0表示必败态
    int tmp=0;
    for(int i=2;i<=2002;i++)
    {
       S.clear();


       for(int j=1;j<i;j++)
       {

           tmp=0;
           ///有偶数堆相同的高度j,添加作为而外的堆,对结果不影响,因为谁要是必胜,加了这些堆他还是必胜的
           ///故奇数堆相同的高度j,多出来的一个堆会作为后继状态影响,故我们异或它的后继状态
           if((i/j)&1) tmp^=SG[j];
           if(i%j)
           tmp^=SG[i%j]; ///不够分为高度j的堆,那么剩余的高为i%j的堆也会作为后继状态影响
           S.insert(tmp);

           ///这里一个堆会拆分成多个堆,跟以往的SG找后继状态有点不同(后继状态只唯一),而这里不唯一
           ///故我们就直接异或了。我们再回顾下SG函数的定义
           ///任意状态 x , 定义 SG(x) = mex(S),其中 S 是 x 后继状态的SG函数值的集合。
           ///如 x 有三个后继状态分别为 SG(a),SG(b),SG(c),那么SG(x) = mex{SG(a),SG(b),SG(c)}。
           ///也就是说每个SG[]它的值就对应了他是必胜还是必败的
           ///那我们这里后继状态不一定唯一(可以分为多个堆),我们可以这样假设一下,
           ///我们就单堆,高度为3,我们可以把它分为个高度为2和1,那么此时它是必败的,
           ///SG[2]^SG[1]=1,即SG[3]=0,必败(0为必败点),其实单堆高度为3不是必败的,我这只是举个例子而已(SG[3]是等于2的)。
           ///这样可能就比较好解释这个抽象的东西

       }

       for(int j=0;;j++)
       {
           if(!S.count(j)){
            SG[i]=j;break;
           }
       }


    }
}


int main()
{

    init();

//    for(int i=1;i<=5;i++)
//        printf("%d ",SG[i]);
//    puts("");
    int n;
    scanf("%d",&n);

    int item,sum=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&item);
        sum^=SG[item];

    }


    if(sum) puts("First");
    else puts("Second");





    return 0;
}

猜你喜欢

转载自blog.csdn.net/LJD201724114126/article/details/89376291