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(); }