ACdream群OJ 1131 Apple 博弈

题目大意:整理为,现在有两个数字n和m,两人每轮可以使得n++或者m++(有且必须选其一),第一个让n^m>=A的人为输。问第一个人是必输、必赢或平局。

思路:先用的sg求,发现平局没法表示。最后直接用0表示必输点、1表示必赢点、2表示平局。

问题的关键在于终止条件的判断。显然当 n>=2 && m>=2时候 子状态是有限且很少的,可以暴力询问所有子状态。

当n==1时,m其实可以取无限大。但是,发现当 (n+1)^m>=A时候,子状态只有一个,而且,显然这种状态为平局。

当m==1时,n<=A,状态有限但是太多。但是当n^(m+1)>=A,子状态只有一个,可以直接通过A-n的奇偶性判断此点状态。

特别的,当一开始n^m>=A时候,是先手必败。

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
typedef long long LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const int INF=100011122;
const double INFF=1e100;
const double eps=1e-8;
const LL mod=20120427;
const int NN=10;
const int MM=1000010;
/* ****************** */

map<pair<int,int>,int>Mmap;
int cnt;
LL A;
int sg[1000000];
//0:lose
//1:win
//2:ping
pair<int,int>temp;

// n^m >= A
bool fun(int n,int m)
{
    if(n==1)
    {
        if(1>=A)
            return true;
        return false;
    }
    LL x=1;
    while(m--)
    {
        x=x*n;
        if(x>=A)
            return true;
    }
    return false;
}

int solve(int n,int m)
{
    temp=MP(n,m);
    int id;
    if(Mmap.count(temp)==0)
    {
        id=++cnt;
        sg[id]=-1;
        Mmap[temp]=id;
    }
    else
        id=Mmap[temp];

    if(sg[id]!=-1)return sg[id];
    if(fun(n,m))
    {
        sg[id]=1;
        return sg[id];
    }
    if(n==1 && fun(n+1,m))
    {
        sg[id]=2;
        return sg[id];
    }
    if(m==1 && fun(n,m+1))
    {
        sg[id]=1-( (A-n)%2 );
        return sg[id];
    }
    int x1=solve(n+1,m);
    int x2=solve(n,m+1);
    if(x1==0 || x2==0)
        sg[id]=1;
    else
    {
        if(x1==1 && x2==1)
            sg[id]=0;
        else
            sg[id]=2;
    }
    return sg[id];
}

int main()
{
    int x,z;
    int n,m;
    while(scanf("%d%d%d",&n,&m,&z)!=EOF)
    {
        Mmap.clear();
        cnt=0;
        A=z;
        if(fun(n,m))
        {
            puts("lose");
            continue;
        }
        x=solve(n,m);
      //  printf("cnt==%d\n",cnt);
        if(x==0)
            puts("lose");
        else if(x==1)
            puts("win");
        else
            puts("draw");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值