bzoj4702: 装箱游戏

Description

Alice和Bob正在玩一个非常无聊的游戏以打发时间。游戏是这样的。初始的时候,有n个箱子和m个物品。箱子、物
品都是不同的。因此有nm种方法把这些物品放到箱子里。两个人轮流操作。每一次操作,游戏者有两种选择:添加
一个新的箱子或者添加一个新的物品。不可以不操作。如果某人操作以后,将物品放入箱子的方法数大于或等于c
,那么这个人就输了。保证最初c > nm。对于一组给定的n和m,假设游戏者足够聪明,请问是先手必胜,还是后手
必胜,还是平局(即无人能获胜)呢?注意,输入文件包含多组测试数据。

Input

第一行包含一个整数T,表示有T组测试数据。
接下来T行,每行包含三个整数n,m,c。
1≤n < c,1≤m≤30,2≤c≤109,1≤T≤5

Output

输出T行,依次表示每组测试数据的答案。若先手必胜输出"Alice",后手必胜输出"Bob",平局输出"Draw"。
有效状态数非常少,可以记忆化搜索或dp
若n=1,m足够大使2^m>=c,则游戏不会结束,故为平局
若m=1,n足够大使n^2>=c,则可以直接判定胜负
一个状态为必胜态,当且仅当存在一个后继状态为必败态,一个状态为必败态,当且仅当没有后继或所有后继为必胜态,否则为平局状态
#include<cstdio>
#include<map>
#include<algorithm>
typedef long long i64;
int T,n,m,c;
std::map<std::pair<int,int>,int>mp;
bool chk(i64 a,int b){
    i64 v=1;
    for(;b&&v<c;b>>=1){
        if(b&1)v=v*a;
        a=a*a;
    }
    return v<c;
}
int calc(int a,int b){
    if(!chk(a,b))return 2;
    if(a==1&&(1ll<<b)>=c)return 1;
    if(b==1&&i64(a)*a>=c)return ((c-a+1&1)<<1);
    std::pair<int,int>st=std::make_pair(a,b);
    if(mp.find(st)!=mp.end())return mp[st];
    int x=calc(a+1,b),y=calc(a,b+1);
    if(!x||!y)return mp[st]=2;
    if(x==2&&y==2)return mp[st]=0;
    return mp[st]=1;
}
int main(){
    for(scanf("%d",&T);T;--T){
        scanf("%d%d%d",&n,&m,&c);
        mp.clear();
        int w=calc(n,m);
        puts(w==0?"Bob":w==1?"Draw":"Alice");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/5981992.html