【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;
}
posted @ 2018-03-06 11:18  ywwyww  阅读(216)  评论(0编辑  收藏  举报