AT_agc002_e

liuboom發表於2024-12-06

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