题目大意:
有n堆糖果,每堆的数量为ai,两个个轮流吃糖果,每一次可以选择将最大的那一堆吃掉或者每一堆都吃一颗。吃掉最后一粒糖果的人会输。问是否先手必胜?
思路:
看样子好像没有地方入手,因为有一种操作是将每一堆都吃掉一颗。发现吃掉
i
i
堆最大的糖果同时也每一堆吃一颗吃了次和顺序并没有关系。于是我们可以建立一种模型,就是将糖果的数量从大到小排序之后,我们看成n个矩阵围成的封闭图形,我们从
(1,1)
(
1
,
1
)
出发,最后走到边界外面的人失败。
然后把SG函数的表打出来,发现一斜行的数值都相同,设当前点为
(i,j)
(
i
,
j
)
证明如下:
若
(i,j)
(
i
,
j
)
先手必胜,那么
(i+1,j)
(
i
+
1
,
j
)
或者
(i,j+1)
(
i
,
j
+
1
)
必有一个先手必败,那么
(i+1,j+1)
(
i
+
1
,
j
+
1
)
必为先手必胜。
若
(i,j)
(
i
,
j
)
先手必败,那么
(i−1,j)
(
i
−
1
,
j
)
和
(i,j−1)
(
i
,
j
−
1
)
必定都为先手必胜,所以
(i−1,j−1)
(
i
−
1
,
j
−
1
)
必定为先手必败。
然后我们就可以一直从
(1,1)
(
1
,
1
)
斜向前怼了,怼到不能怼为止。但是这个最后的点的SG值要怎么求呢?
发现这个点只能一直朝着一个方向走,于是我们两个方向都判断一下奇偶性就好了。
/*======================
* Author : ylsoi
* Problem : AGC02E
* Algorithm : SG
* Time : 2018.6.2
* ===================*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<climits>
using namespace std;
void File(){
freopen("AGC02E.in","r",stdin);
freopen("AGC02E.out","w",stdout);
}
template<typename T>bool chkmax(T &_,T __){return _<__ ? (_=__,1) : 0;}
template<typename T>bool chkmin(T &_,T __){return _>__ ? (_=__,1) : 0;}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define mem(a) memset(a,0,sizeof(a))
#define inf INT_MAX
const int maxn=1e5+10;
int n,a[maxn],SG[1010][1010];
bool cmp(int _,int __){return _>__;}
bool judge(int x,int y){return x<=n && y<=a[x];}
int main(){
File();
scanf("%d",&n);
REP(i,1,n)scanf("%d",&a[i]);
sort(a+1,a+n+1,cmp);
int px=1,py=1,step1=0,step2=0;
while(judge(px+1,py+1))++px,++py;
while(judge(px+step1,py))++step1;
while(judge(px,py+step2))++step2;
if(step1%2==0 || step2%2==0)puts("First");
else puts("Second");
return 0;
}