AT_agc002_e
AT_agc002_e
[AGC002E] Candy Piles
题面翻译
桌上有 \(n\) 堆糖果,第 \(i\) 堆糖果有 \(a_i\) 个糖。两人在玩游戏,轮流进行,每次进行下列两个操作中的一个:
-
将当前最大的那堆糖果全部吃完;
-
将每堆糖果吃掉一个;
吃完的人输,假设两人足够聪明,问谁有必胜策略?
输出 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();
}

浙公网安备 33010602011771号