題目簡述spa
給定n個數,兩我的輪流取數,和以前兩我的的取的數或起來,誰不能取數或者誰取到的數和以前的數或值爲511誰輸,問誰可以贏?code
題解blog
剛開始的想法是直接搜,不過須要記錄取過的值的狀態,2^50顯然超時。。。對於當前或值cur,或上一個數num,只有兩種狀況,要麼是 cur|num==cur,get
對於這種數,只是把這個狀態直接給下一個玩家,起到延緩一步的做用,他們的選取順序對局面沒有影響,能夠先所有輪流取掉,若是這種數的個數大於當前已經取的數的數量,那麼咱們還能夠選擇這種數,若是選擇這個數能夠致使下一個局面必敗,那麼當前這個局面能夠必贏。第二種狀況就是cur|num!=cur,num確定是沒有取過的,若是存在一個數num致使下一個局面必敗,那麼當前這個局面也是必勝的。若是下一個局面必勝,那麼當前局面就是必輸的,咱們能夠用記憶化搜索實現上述過程~~~string
代碼:it
1 vector<int>card; 2 int dp[55][555], n; 3 int dfs(int th, int mask) 4 { 5 if (mask == 511) return 1; 6 if (th == n) return 0; 7 if (~dp[th][mask]) return dp[th][mask]; 8 int cnt = 0; 9 for (int i = 0; i < n; i++) if ((card[i] | mask ) == mask) cnt++; 10 if (cnt > th && !dfs(th + 1, mask)) return dp[th][mask] = 1; 11 for (int i = 0; i < n; i++) if ((card[i] | mask ) != mask) 12 { 13 if (!dfs(th + 1, mask | card[i])) return dp[th][mask] = 1; 14 } 15 return 0; 16 } 17 class FiveHundredEleven 18 { 19 public: 20 string theWinner(vector <int> cards) 21 { 22 card = cards; 23 n = card.size(); 24 memset(dp, -1, sizeof(dp)); 25 return dfs(0, 0) ? "Fox Ciel" : "Toastman"; 26 } 27 };