A题 Alice and Bob
我们知道当面临两堆石头数量为(0,0)时为失败,那么如果能一次操作能取光石头此时为必胜态,我们用一个二维数组f[i][j]来表示第一堆石头数量为i第二堆石头数量为j的情况,f[i][j]=1表示状态面临两堆石头数量为i,j时可以一步取光石头,f[i][j]=0表示状态面临两堆石头数量为i,j时无法一次取光石头。初始f[0][0]=0,根据题目f[k][sk]或f[sk][k]一定能够一次性取完,我们可以从(i=0,j=0)开始自小变大枚举s与k找出所有先手必胜的状态,由于是自小变大枚举所以发现有f[i][j]=0就发现了一个必败的局面再对它枚举s与k,当初始状态f[i][j]=1时Alice显然获胜,那么现在面临的问题是当初始状态为f[i][j]=0时Alice能否获胜,由于Alice一次取不完石头,又要保证自己一次取完后不输,即需要满足取完石子后f[i-k][j-sk]=0或者f[i-sk][j-k]=0,这显然是不可能的,因为对于每一个f[i][j]==0其f[i+k][j+s*k]=1(同f[0][0]),时间复杂度为O(n^4),显然不满足题目数据,但是这里大家需要知道一个结论:对于一个的i只存在至多一种j后手能够获胜
证明如下:
若存在(i,q)(i,p)(p>q)满足后手胜,那么Alice只需将(i,p)->(i,q)即可获胜,不满足后手胜的条件。
这样我们的时间复杂度大约在O(n^3),本题数据量为5000,勉勉强强过的去,但是需要避免cin等操作,数组也需要开成bool的来节省运算时间。

#include<iostream>
#include<stdio.h>
using namespace std;
bool f[5001][5001];
int main()
{    
    for(int i=0;i<=5000;i++)//自小到大枚举i,j
    for(int j=0;j<=5000;j++)
    {
        if(f[i][j]==0)//对于每种必败态进行拓展
        {//f[i][j]与f[j][i]是等价的
            for(int k=1;k+i<=5000;k++)for(int s=0;s*k+j<=5000;s++)f[i+k][j+s*k]=1;
            for(int k=1;k+j<=5000;k++)for(int s=0;s*k+i<=5000;s++)f[i+s*k][j+k]=1;
        }
    }
    int t,n,m;
    cin>>t;
    while(t--)
    {
       scanf("%d%d",&n,&m);
        if(f[n][m]==0)
        {
            puts("Bob");
        }
        else 
            puts("Alice");
     }
    return 0;
}