题解:
如果最左边的石子数目为1,那么只能拿1个石子,那么它的必胜必败态就和下一个位置的必胜必败态相反
如果最左边的石子数目大于1,那么可以全部拿掉,可以拿得只剩下1个,这两种状态一定存在一个必败态,所以它是必胜态。
题不难,就是bug写的太多了,哎…,最近状态真心不好(就是太菜了)…
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<set>
#include<map>
#include<iterator>
#include<queue>
#include<vector>
#include<string>
using namespace std;
typedef long long ll;
const int N=1e6+10;
const long long INF=1e18;
const double eps=0.0000001;
int vis[40][40][40];
int a[N],b[N],d[N];//a储存数字,d储存每个状态的数字顺序
int ans[N];//ans储存非 1数字的下标序列
int main()
{
int x=0;
int y=1;
int n;
int c=0,h=0,s=-1,s1;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
if(a[i]!=1)
{
c=1;
ans[++h]=i;
}
}
for(int i=0;i<n;i++)
{
if(c==0)//如果全为一的情况,特判
{
if((n+1)%2)
printf("Second\n");
else
printf("First\n");
}
else
{
s=-1;
for(int j=y;j<=h;j++)
{
d[j]=(ans[j]-i+n)%n;//环状,循环状态
s1=(ans[1]-i+n)%n;//记录第一个非 1 的下表
if(x==1)
{
break;
}
if(ans[j]-i>=0)
//滚动数组,变换后的坐标值当ans[j]-i>=0时,一定是第一个非一的数字
{
s=d[j];
y=j;
break;//由于目的找到第一个非一的数字,所以没必要记录之后的下标
}
}
if(s!=-1&&x==0)
{
if((s)%2==0)
{
printf("First\n");
}
else
printf("Second\n");
}
else
{
x=1;
//优化,画图理解一下,如果s1是第一个非1的数字,那么之后的所有序列中,s1都是第一个非一数字
if((s1)%2==0)
{
printf("First\n");
}
else
printf("Second\n");
}
}
}
}
标程:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int n, a[maxn], ans[maxn], flag;
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)cin >> a[i], a[n + i] = a[i], flag = flag ? 1 : (a[i] != 1);
if(!flag)
{
if(n&1)for(int i = 1; i <= n; i++)cout<<"First"<<endl;
else for(int i = 1; i <= n; i++)cout<<"Second"<<endl;
return 0;
}
for(int i = 2 * n; i >= 1;i--)if(a[i] > 1)
{
ans[i] = 1;
int j = i - 1;
for(; j >= 1 && a[j] == 1; j--)
ans[j] = -ans[j + 1];
i = j + 1;
}
for(int i = 1; i <= n; i++)
if(ans[i] > 0)cout<<"First"<<endl;
else cout<<"Second"<<endl;
return 0;
}