1. 程式人生 > >【博弈】AGC002E Candy Piles

【博弈】AGC002E Candy Piles

題意:

給出N個數,兩人依次選擇一種操作: 1、刪去最大的一個數 2、所有數-1

不能走的算獲勝,求誰必勝。

分析:

有趣。。。這題真心有趣。。。

首先,把這N個數從大到小排序,畫成一個圖: 這裡寫圖片描述 每種操作就相當於:刪去最左邊一列,或刪去最下面一行。

然後觀察剩餘部分的左下角座標:發現它是從(0,0)出發,每次向上走(刪去最下面一行),向右走(刪去最左邊一列),最終到達邊界的一條路徑。 這裡寫圖片描述

所以就可以把每個點存一個NP狀態。 邊界的都為必勝,然後按照NP狀態的定義進行轉移。

但就這麼轉移肯定會T

然後可以把NP狀態畫一下,發現:每一個斜對角線(除去邊界)NP狀態都是一樣的 這裡寫圖片描述

證明很簡單: 如果點(x,y)是必勝,那麼(x+1,y)或(x,y+1)是必敗,但無論誰是哪個必敗,都必須使(x+1,y+1)必勝,因為(x+1,y)可以向右走到達(x+1,y+1),(x,y+1)可以向上走到達(x+1,y+1)。

如果點(x,y)是必敗,那麼(x+1,y)與(x,y+1)都為必勝,根據上面所證明的,則(x+2,y+1),(x+1,y+2)均為必勝,那麼(x+1,y+1)則為必敗。

所以就可以直接根據(0,0)所在的斜對角線,求出其對應的未到達邊界的最高的一個點,然後從那個點出發,觀察其上方還剩多少個點,右方還剩多少個點,當且僅當兩者均為奇數時,答案為必敗,否則為必勝 這裡寫圖片描述

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
int a[MAXN];
bool cmp(int x,int y){
    return x>y;
}
int main(){
    int n,m,q;
    SF("%d",&n);
    for(int i=1;i<=n;i++)
        SF("%d"
,&a[i]); sort(a+1,a+1+n,cmp); a[0]=a[1]; for(int i=0;;i++) if(i+2>a[i+2]){ int x=i; int len1=a[i+1]-x; int len2=1; for(;a[i+len2+1]>x;len2++); if(len1%2==1&&len2%2==1) PF("Second"); else PF("First"); break; } }