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 @   liuboom  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示