若干堆石子排成一行,两个人轮流操作,先手可以操作最左边的,后手可以操作最右边的,每次可以在一堆石子中取走至少一个石子。最后不能操作的人算输。
问谁胜。
(Tle 100,nle 100)
显然,一个人当前操作的堆中,石子数越多,他越有可能胜利。
于是每个人操作只会有两种情况:将整堆取完;取一个石子续命。
设(f_{l,r,0})表示:操作区间([l,r]),轮到先手操作,此时([l+1,r])中石子没有动过,求使得先手必胜的最小的(a_l)是多少。再设(f_{l,r,1})表示类似的含义。
分类讨论(以(f_{l,r,0})为例):
- 若取完整堆必胜,即(f_{l+1,r,1}>a_r),则取整堆,返回(1)。
- 否则即(f_{l+1,r,1}le a_r)。先手取一个轮到后手,此时再讨论:
- (f_{l-1,r,0}>a_l-1),则取整堆,返回(a_l+1)。
- (f_{l-1,r,1}le a_l-1)。到了这里我们得到了两个不等式,后面的操作就是(a_r)和(a_l)轮流减一,直到其中一个不等式被破坏。设先手必胜时(a_l)为(x),则有(x-1-f_{l,r-1,0}ge a_r-f_{l+1,r,1}),这样就可以得到(x)的最小值。
这样就可以在(O(n^2))时间内解决这题。
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 105
int n;
int a[N];
int f[N][N][2];
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
for (int i=n;i>=1;--i){
f[i][i][0]=f[i][i][1]=1;
for (int j=i+1;j<=n;++j){
if (a[i]==1)
f[i][j][0]=(f[i+1][j][1]>a[j]?1:a[i]+1);
else
f[i][j][0]=(f[i+1][j][1]>a[j]?1:f[i][j-1][0]>a[i]-1?a[i]+1:a[j]-f[i+1][j][1]+f[i][j-1][0]+1);
if (a[j]==1)
f[i][j][1]=(f[i][j-1][0]>a[i]?1:a[j]+1);
else
f[i][j][1]=(f[i][j-1][0]>a[i]?1:f[i+1][j][1]>a[j]-1?a[j]+1:a[i]-f[i][j-1][0]+f[i+1][j][1]+1);
}
}
// for (int i=1;i<=n;++i){
// for (int j=1;j<=n;++j)
// printf("(%d,%d) ",f[i][j][0],f[i][j][1]);
// printf("
");
// }
if (f[1][n][0]<=a[1])
printf("First
");
else
printf("Second
");
}
return 0;
}