[??记录]AT1999 [AGC002E] Candy Piles
command_block
2021-04-21 11:02:48
**题意** : 初始时有 $n$ 堆石子,第 $i$ 堆有 $a_i$ 个。
两人轮流操作,每次进行下列两个操作中的一个 :
- 将每堆石子拿去一个
- 拿去最多的一堆
无法操作者输,问是否先手必胜。
$n\leq 10^5,\ a\leq 10^9$ ,时限$\texttt{2s}$。
------------
将 $a$ 从大到小排序,绘制直方图,两种操作分别对应去掉一行或一列。
那么问题变为,在这个直方图上,每一步可以向上或向右走,走完最后一步者输。
可以大力递推出 $P/N$ 态,如下图 :
![](https://cdn.luogu.com.cn/upload/image_hosting/4xupn0da.png)
发现规律 : 对于某个格子,若右上方有格子,那么状态与右上方的格子相同。可以归纳证明。
于是,我们只需要关心有色部分的状态。
橙色位置的状态是边界,中间的黄色段容易递推得到。
```cpp#include<algorithm>
#include<cstdio>
#define MaxN 100500
using namespace std;
int n,a[MaxN];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)scanf("%d",&a[i]);
sort(a+1,a+n+1);reverse(a+1,a+n+1);
int p=0;
for (int i=1;i<=n;i++)
if (a[i]>=i)p=i;
//边界上的点为 (p,p)
if (p!=a[p+1]&&a[p]==p){puts("Second");return 0;}
else {
int c=1;bool fl=0;
for (int i=p;a[i+1]==p;i++)c++;
if (!(c&1))fl|=1;
if (a[p]>p&&((a[p]-p)&1))fl|=1;
puts(fl?"First":"Second");
}return 0;
}
```