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