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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值