題目連接ios
博弈c++
時間複雜度O(N)
算法
1.這道題乍一看覺得用Nim博弈直接套用就能夠了,結果經過題意發現並非。題目中要求取石子時只能從下標最小的那一堆開始取,也就是說一堆一堆的取,不能跳着取。spa
2.分析完題意,咱們知道最後取完最後一堆的人必勝。那麼怎麼分析誰最後會贏呢?.net
若是隻有一堆的話,很容易得出第一我的獲勝。關鍵在於如何分析多堆的狀況。code
爲了方便,咱們將每一堆中首先取的人稱爲先手,而後取的人是後手,下面咱們來進行分類討論:blog
分類討論後發現,一共就上面兩大類狀況。那麼該怎麼作呢?這裏是題目的一個難點。ci
對於先手,當該石堆中石子個數超過1而且還有其餘的石堆時,他能夠根據實際狀況選擇在下一堆中成爲先手仍是後手。可是當石堆中石子個數爲1時他別無選擇,只能是在下一堆中成爲後手。因此說石子個數爲1的石堆爲轉折點。get
既然當某石堆石子個數大於1時先手能夠任意選擇在下一堆中他的身份,因此若是還有其餘石堆,那麼該先手必勝。(由於他掌握着主動權,因此他徹底能夠根據剩餘的石堆數來選擇接下來的身份,至於怎麼選咱們不用考慮)io
當石子個數等於1時,先手變成後手,後手變成先手。
3.總結一下,咱們只需從頭判斷每一堆的石子的個數,若個數爲1,則繼續循環,直到循環完。若是循環完了,說明都爲1,這時只需判斷石堆個數便可;若出現個數不爲1的,則先手必勝,跳出循環便可。
#include<iostream> using namespace std; const int N = 1e5 + 10; int t, n; int a[N]; int main() { cin >> t; while(t--) { cin >> n; for(int i = 0; i < n; i++) cin >> a[i]; int first = 1, second = 0; bool flag = false; for(int i = 0; i < n; i++) { if(a[i] == 1) { if(first) { first = 0; second = 1; } else { first = 1; second = 0; } } else { if(first) puts("First"); else puts("Second"); flag = true; break; } } if(!flag) { if(n % 2 == 1) puts("First"); else puts("Second"); } } }
思路來源(注意這裏「先手」的定義與思路來源鏈接裏的「先手"定義不一樣)