题目大意:整理为,现在有两个数字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;
}