AT_agc002_e

AT_agc002_e

[AGC002E] Candy Piles

题面翻译

桌上有 \(n\) 堆糖果,第 \(i\) 堆糖果有 \(a_i\) 个糖。两人在玩游戏,轮流进行,每次进行下列两个操作中的一个:

  1. 将当前最大的那堆糖果全部吃完;

  2. 将每堆糖果吃掉一个;

吃完的人输,假设两人足够聪明,问谁有必胜策略?

输出 First(表示先手必胜)或 Second(表示后手必胜)

【数据范围】

  • \(1\leq n\leq10^5\)
  • \(1\leq a_i\leq10^9\)

---------------------------------------------------------------------------------------

首先,我们将所有点排序之后得到一张网格图:

1 1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1
1 1 1
1 1

设(1,1)为初始状态

不难发现,对于我们的两种操作:

1.将当前最大的那堆糖果全部吃完 等价于 (x,y)->(x+1,y)

将每堆糖果吃掉一个 等价于 (x,y)->(x,y+1)
(在这里(x,y)表示第x行,第y列)

得到这个图之后,先别急,我们先来证明一个东西:

设f[x][y]=0/1表示当前点必胜或者必败,则f[x][y]=f[x+1][y+1]

首先,学过博弈论的我们应该知道:

1:一个状态是必败态,当且仅当它的所有后继状态都是必胜态;

2:一个状态是必胜态,当且仅当它的后继状态存在一个必败态。

若f[x][y]=1:
f[x+1][y]=0或f[x][y+1]=0;
若f[x+1][y]=0,则f[x+1][y+1]=f[x+2][y]=1;
若f[x][y+1]=0,则f[x+1][y+1]=f[x][y+2]=1;
所以f[x+1][y+1]=1;
则当f[x][y]=1时,f[x][y]=f[x+1][y+1]得证

若f[x][y]=0:
则f[x+1][y]=f[x][y+1]=1;
则f[x+2][y+1]=f[x+1][y+2]=1;
则对于f[x+1][y+1]:
他的两个后继f[x+2][x+1]=f[x+1][y+2]=1;
满足:

1:一个状态是必败态,当且仅当它的所有后继状态都是必胜态;

所以f[x+1][y+1]=0;
所以f[x][y]=f[x+1][y+1]在f[x][y]=0时得证

综上f[x][y]=f[x+1][y+1]得证

solution:

我们先将(1,1)沿着对角线跳到(x,x):
x满足(x,x)在方格图中存在且(x+1,x+1)不存在
(x,x)即为对角线上能跳到行列最大的点

接下来对这个状态进行讨论:

记这个点(x,x)到当前行最右边的列的距离为len_y
记这个点(x,x)到当前列最下边的行的距离为len_x

由题目可知:

吃完的人输

所以只要len_y,len_x中只要有一个偶数,先手就赢了;
反之必输

然后这题就做完了

Code:

#include<bits/stdc++.h>
const int N=1e5+5;
using namespace std;
int a[N];
bool cmp(int a1,int a2){return a1>a2;};
int n;
string s[2]={"Second","First"};
void work()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	sort(a+1,a+1+n,cmp);
	int x=1,y=1;
	while(a[x+1]>=y+1){x++,y++;};
	int len_x=x,len_y=a[x]-x;
	while(a[len_x]>=y){len_x++;};
	len_x-=x;
	len_x--;
	bool ans=0;
	if(len_x&1||len_y&1)
	ans=1;
	cout<<s[ans];
}
int main()
{
	work();
}
posted @ 2024-12-06 11:45  liuboom  阅读(26)  评论(0)    收藏  举报