Description
小花梨有?堆石子,第?堆石子数量为??,?堆石子顺时针编号为1 − ?(如图) 。 游戏将进行?轮,每轮游戏单独进行,互不干扰,每轮初始时第?堆石子数目为??。 第?轮从编号为?的那堆石子为起点,顺时针来取石子。两人轮流取石子,不可不取,最少取 一个石子,最多把当前这一堆取完,只有取完一堆后才走到下一堆石子。走完一圈后石子都 被取完,不能取石子的人就失败。假设两人以最优策略进行取石子操作,请分别输出?轮游 戏是先手胜还是后手胜。
Input
第一行为正整数?,表示石子的堆数 (1 ≤ ? ≤ 100000) 第二行输入?个正整数表示每一堆的石子数目??(1 ≤ ?? ≤ 109)
Output
输出?行,第?行表示第?轮游戏的结果。如果先手胜则输出"?????",后手胜输出"??????"。
Example
Sample Input
3
2 1 3
Sample Output
First
Second
First
Sample Input
2
2 2
Sample Output
First
First
Note
样例1: 游戏进行3轮 第1轮游戏石子堆下标的顺序为1 2 3,此时石子数目按顺序为2 1 3,先手胜 第2轮游戏石子堆下标的顺序为2 3 1,此时石子数目按顺序为1 3 2,后手胜 第3轮游戏石子堆下标的顺序为3 1 2,此时石子数目按顺序为3 2 1,先手胜
比赛时候没做出来T.T,目前写博弈还是有点困难,,,主要是不会算sg值,后来补题听人讲了讲好像懂了0.0
思路:
举前三堆的例子:
只有1堆石子:先手必胜
有2堆石子:(1)第一堆只有一个,必须把第一堆取完,后手变为必胜态,即先手必败。
(2)第一堆有多个,可以让第一堆变为一个,那么后手为(1)的状态,即必败态,那么先手必胜。
有3堆石子:(1)第三堆有一个石子,这时需要看第二堆的状态,若为上面(1)的情况,那么先手必胜,若第二堆为上面(2)的情况,那么先手必败。
(2)第三堆有多个石子,若第二堆为上面(1)的情况,可以直接拿完所有石子,让后手到达必败态,若第二堆为上面(2)的情况,可以让当前堆剩下一个石子,让后手到达必败态,即这时不用考虑前面的情况,先手必胜。
总结:若第一堆(每一轮游戏的第一堆)石子数目不为1,那么先手必胜(因为必胜必败态是交替的,可以通过控制取的石子的数目从而控制胜负,如上面第三堆石子(2)的情况)。
若为1,那么需计算从第一堆开始有多少连续的只有1个石子的堆,若为偶数,先手必胜,(因为面对数目不为1那堆石子的人还是先手),若为奇数,先手必败。
注意:计算前缀1的时候需要一个加长数组提前处理处理,否则会超时。而且所有堆都为1的时候需要特判,因为这时候和上面前缀1的结论反着。若为奇数的话,先手必胜。偶数的话,先手必败。
#include<iostream>
using namespace std;
#define N 100005
int a[N<<1]; //需要开两倍的空间
int sum[N<<1];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i+n]=a[i];
}
for(int i=2*n;i>=1;i--)
{
if(a[i]==1)
sum[i]=sum[i+1]+1;
sum[i]=min(sum[i],n); //让最大值维护在n
}
for(int i=1;i<=n;i++)
{
if(sum[i]==n) //若所有堆都为1,让值加1,因为和前缀1数目的结论相反
sum[i]++;
if(sum[i]%2==0)
cout<<"First"<<endl;
else
cout<<"Second"<<endl;
}
return 0;
}