1. 程式人生 > >SRM div1 MagicNim(博弈論)

SRM div1 MagicNim(博弈論)

col 保持 clu blog stream ant 現在 ios 個數

題目大意:

給出n+1堆石子,前n堆石子的數量是a[i],最後一堆只有1個石子,但是具有魔力

拿走該石子的一方可以選擇接下來是進行普通的Nim遊戲還是anti-nim遊戲

問是先手必勝還是必敗

首先拿全是1的情況熟悉一下規則

如果全是1,那麽無論有幾堆,先手都是必勝的

因為如果有奇數個1,那麽Alice直接拿掉魔力石子,然後選擇不改變遊戲,那麽他還是贏的

如果有偶數個1,那麽Alice直接拿掉魔力式子,然後選擇改變遊戲,於是他還是贏的。

然後回憶一下anti-nim的先手必勝條件(這裏的SG不考慮多魔法石子的那一堆)

SG為0,且所有石子均為1

SG不為0,且存在一堆石子大於1

所以,如果不全是1,且SG為0的話,Alice是必輸的,因為他取魔力石子後,仍然無法改變必輸的情況

所以現在情況只有不全是1,且SG不為0

註意到這個時候任何一方如果直接取魔力石子,都是必敗的

所以雙方應該會保持SG不為0,然後進行對峙

首先考慮所以石子的數量不超過3

那麽SG函數的值就只有3個,1,2,3

當SG為1或3的時候,肯定有一種取法使得SG為2

而SG為2的最終情況是2附加一個魔力石子,這種情況是必敗的

所以當石子的數量不超過3時,SG=2先手必敗,反之必勝

接下來考慮石子的數量超過3,也就是有4和4以上的數

那麽SG函數的值可以分成1和超過1的那些情況

如果當前SG值為1,那麽只能把它變成超過1的值,然而對手又可以把它變回到1

我們考慮假設只有1個超過3的數,那麽這時候SG值肯定是大於3的

直接改變這個數,我們可以使得接下來的局面變成SG=2

也就是說,如果只有1個超過3的數,那麽就是先手必勝

那麽如果SG值為1,且我們知道存在超過3的數,那麽超過3的數的數量必定至少有2個

也就是說,經過不斷地對峙,原來SG值為1的話,現在SG值仍然為1

但是經過了很多減少,一定會達到這個局面

即SG值為1,且超過3的數量只有2個

當這2個其中的一個數減到4以下時,就變成了只有1個超過3的數

即SG->1->3以上->2(最終結果)

也就是說SG如果為1,必定會轉化成2,那麽SG=1就是必敗局面,而其他情況是必勝局面

最後結論就是

如果有大於3的數,那麽SG=1必敗

如果沒有,那麽SG=2必敗

(PS:題解的思路沒有太明白,不知道是怎麽想到右移1位然後分類的,然後莫名分類就分出來了orz)

#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <sstream>
#include <typeinfo>
#include <fstream>

using namespace std;

class MagicNim {
    public:
    string findWinner(vector<int> a) {
        sort(a.begin(), a.end());
        int n = a.size(), sg = 0;
        for(int i = 0; i < n; i++) sg ^= a[i];
        if(a[n-1] >= 4) return (sg == 1 ? "Bob" : "Alice");
        else return (sg == 2 ? "Bob" : "Alice");
    }
};

SRM div1 MagicNim(博弈論)