【AGC002E】Candy Piles 博弈论

题目大意

  有(n)堆糖果,第(i)堆有(a_i)个。

  两个人轮流决策,决策分为两种:

   1.选择糖果数最多的一堆糖果,并把这堆糖全吃了。

   2.在每堆非空的糖果堆里拿一颗糖吃掉。

  吃掉最后一颗糖的人输。问你先手必胜还是先手必败。

  (nleq 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
");
	else
		printf("Second
");
	return 0;
}
原文地址:https://www.cnblogs.com/ywwyww/p/8513316.html