问题 D: 小花梨的取石子游戏
强调
本人是一名小弱鸡,如果有错误,请各位大佬指出。第一次写,希望大家能够提出不足之处。
题目描述
小花梨有n堆石子,第i堆石子数量为ai,n堆石子顺时针编号为1−n(如图)。
游戏将进行n轮,每轮游戏单独进行,互不干扰,每轮初始时第i堆石子数目为ai。
第i轮从编号为i的那堆石子为起点,顺时针来取石子。两人轮流取石子,不可不取,最少取一个石子,最多把当前这一堆取完,只有取完一堆后才走到下一堆石子。走完一圈后石子都被取完,不能取石子的人就失败。假设两人以最优策略进行取石子操作,请分别输出n轮游戏是先手胜还是后手胜。
输入
第一行为正整数n,表示石子的堆数(1≤n≤100000)
第二行输入n个正整数表示每一堆的石子数目ai(1≤ai≤109)
输出
输出n行,第i行表示第i轮游戏的结果。如果先手胜则输出"First",后手胜输出"Second"。
样例输入
3
2 1 3
样例输出
First
Second
First
提示
游戏进行3轮
第1轮游戏石子堆下标的顺序为1 2 3,此时石子数目按顺序为2 1 3,先手胜
第2轮游戏石子堆下标的顺序为2 3 1,此时石子数目按顺序为1 3 2,后手胜
第3轮游戏石子堆下标的顺序为3 1 2,此时石子数目按顺序为3 2 1,先手胜
解题思路:这道题一开始让我思考了很久,但是多设计几组样例就可以总结出一个规律出来。
1.从任意一堆开始拿,只要开始的这一堆不是1,就对于先手来说一定是必胜态,即一定是先手必胜。
证明:假设从第i堆开始拿,对于剩下的n-1堆来说,双方都执行最优解,假设是后手必胜,,那么只要先手的一方在第i堆的时候拿a[i]个,那么后手的那一方在剩下的n-1堆中就变为了先手,即对于所有的n堆是先手必胜。再假设对于剩下的n-1堆先手必胜,那么只要先手的一方在第i堆是拿a[i]-1个,那么对于剩下的n-1堆来说,第i堆的先手方变成了后手方,即对于所有的n堆来说 还是先手必胜。综上所述,知道开始拿的第i堆不是1个,就一定是先手必胜。
2.假设第i堆中只有一个石头,那么对于游戏双方,先手的那方是没有什么操作空间的,他只能够拿走那一个石头,那么对于剩下未拿的石头堆来说,先后手双方交替了。假设所有的石头堆都只有一个石头,那么双方对于每一堆石头都只能一次性全部拿光,即从第i堆开始拿到第j堆后,双方的先后手权力交换了j-i次,如果交换的次数为偶数的话,那么相当于先手权没有发生交换,如果是奇数,相当于先手权发生交换。那么对于剩下的石头堆就可以变为第一种情况,即先手必胜。
下列是AC代码
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N=100000;
int a[N+5];
int b[2*N+5];
int main()
{
int x,flag=0;
cin>>x;
for(int i=0;i<x;i++)
{
scanf("%d",&a[i]);
a[i+x]=a[i];
if(a[i]!=1) flag=1;
}
for(int j=2*x-1;j>=0;j--)
{
if(a[j]==1) b[j]=b[j+1]+1;
else b[j]=0;
}
for(int i=0;i<x;i++)
{
if(flag==0)
{
if(x%2==0) printf("Second\n");
else printf("First\n");
}
else
{
if(a[i]!=1) printf("First\n");
else
{
if(b[i]%2!=0) printf("Second\n");
else printf("First\n");
}
}
}
return 0;
}*