[AGC02E]Candy Piles——博弈论SG函数 大佬们的博客 Some Links

题目大意:

有n堆糖果,每堆的数量为ai,两个个轮流吃糖果,每一次可以选择将最大的那一堆吃掉或者每一堆都吃一颗。吃掉最后一粒糖果的人会输。问是否先手必胜?

思路:

看样子好像没有地方入手,因为有一种操作是将每一堆都吃掉一颗。发现吃掉 i 堆最大的糖果同时也每一堆吃一颗吃了 j 次和顺序并没有关系。于是我们可以建立一种模型,就是将糖果的数量从大到小排序之后,我们看成n个矩阵围成的封闭图形,我们从 ( 1 , 1 ) 出发,最后走到边界外面的人失败。
然后把SG函数的表打出来,发现一斜行的数值都相同,设当前点为 ( i , j ) 证明如下:
( i , j ) 先手必胜,那么 ( i + 1 , j ) 或者 ( i , j + 1 ) 必有一个先手必败,那么 ( i + 1 , j + 1 ) 必为先手必胜。
( i , j ) 先手必败,那么 ( i 1 , j ) ( i , j 1 ) 必定都为先手必胜,所以 ( i 1 , j 1 ) 必定为先手必败。
然后我们就可以一直从 ( 1 , 1 ) 斜向前怼了,怼到不能怼为止。但是这个最后的点的SG值要怎么求呢?
发现这个点只能一直朝着一个方向走,于是我们两个方向都判断一下奇偶性就好了。

/*======================
 * Author : ylsoi
 * Problem : AGC02E
 * Algorithm : SG
 * Time : 2018.6.2
 * ===================*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<climits>
using namespace std;
void File(){
    freopen("AGC02E.in","r",stdin);
    freopen("AGC02E.out","w",stdout);
}
template<typename T>bool chkmax(T &_,T __){return _<__ ? (_=__,1) : 0;}
template<typename T>bool chkmin(T &_,T __){return _>__ ? (_=__,1) : 0;}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define mem(a) memset(a,0,sizeof(a))
#define inf INT_MAX
const int maxn=1e5+10;
int n,a[maxn],SG[1010][1010];
bool cmp(int _,int __){return _>__;}
bool judge(int x,int y){return x<=n && y<=a[x];}    
int main(){
    File();
    scanf("%d",&n);
    REP(i,1,n)scanf("%d",&a[i]);
    sort(a+1,a+n+1,cmp);
    int px=1,py=1,step1=0,step2=0;
    while(judge(px+1,py+1))++px,++py;
    while(judge(px+step1,py))++step1;
    while(judge(px,py+step2))++step2;
    if(step1%2==0 || step2%2==0)puts("First");
    else puts("Second");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/80549421
今日推荐