【AGC002E】Candy Piles 博弈论
题目大意
有\(n\)堆糖果,第\(i\)堆有\(a_i\)个。
两个人轮流决策,决策分为两种:
1.选择糖果数最多的一堆糖果,并把这堆糖全吃了。
2.在每堆非空的糖果堆里拿一颗糖吃掉。
吃掉最后一颗糖的人输。问你先手必胜还是先手必败。
\(n\leq 100000\)
题解
又是一个打表结论题。
先把\(a_i\)从大到小排序。
设\(f_{i,j}\)为删掉前\(i\)大,每堆删掉\(j\)个后是先手必胜还是先手必败。先把所有的\(f_{i,j}\)算出来。
如果都删完了,就先手必胜。
打个表可以发现,一条斜线上的结果相同。
这个结论还是挺好证的。这里就不证了。
直接找到\((0,0)\)对应的是哪个点\((i,i)\),算出这个点到上方和右方轮廓的距离,只要有一个是偶数,就先手必胜。
时间复杂度:\(O(n)\)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
int a[100010];
int main()
{
#ifdef DEBUG
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
#endif
int n;
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1,greater<int>());
int ans;
a[0]=a[1];
for(i=0;i<=n;i++)
if(a[i+1]<=i)
{
ans=(a[i]-i)&1;
int j=i+1;
while(j<=n&&a[j]==i)
j++;
if((j-i+1)&1)
ans=1;
break;
}
if(ans)
printf("First\n");
else
printf("Second\n");
return 0;
}