题目连接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"); } } }
思路来源(注意这里“先手”的定义与思路来源链接里的“先手"定义不一样)