HDU - 4111 Alice and Bob 求SG值

題目:有N堆石頭,可以把兩堆合成一堆,也可以把一堆去掉一個。問先手必勝還是先手必敗

思路:所有石子個數大於1的石子堆ai可以看成一堆石子數爲sigma(ai)+n-1的堆,因爲個數大於1的石子堆的合併,對方是無法阻擋的。但是1是可以阻擋的。

每次的操作有:

讓石子數 爲1的堆數減1

合併堆的石子數減1

合併兩個個數爲1的石子堆

把1合併到合併堆上去

代碼:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f
//0x3f3f3f3f

const int maxn=6e4+50;
int sg[55][maxn];
int get_sg(int x,int y){
    if(sg[x][y]!=-1)
        return sg[x][y];
    if(y==1) return sg[x][y]=get_sg(x+1,0);
    sg[x][y]=0;
    if(x>=1&&get_sg(x-1,y)==0)
        sg[x][y]=1;
    else if(y>0&&get_sg(x,y-1)==0)
        sg[x][y]=1;
    else if(x>=1&&y>0&&get_sg(x-1,y+1)==0)
        sg[x][y]=1;
    else if(x>=2&&((y==0&&get_sg(x-2,y+2)==0)||(y>0&&get_sg(x-2,y+3)==0)))
        sg[x][y]=1;
    return sg[x][y];
}
int main(){

    int T,cas=0,n,cnt,sum,x;
    mm(sg,-1);
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        cnt=sum=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            if(x==1) cnt++;
            else sum+=(x+1);
        }
        if(sum) sum--;
        int ans=get_sg(cnt,sum);
        if(ans>0) printf("Case #%d: Alice\n",++cas);//先手必勝
        else printf("Case #%d: Bob\n",++cas);//先手必敗
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章