这道题以一个基准的必败点为单位。
sg[i][j]的意思是:这两堆石子分别剩下i块石头和j块石头的时候如果是1代表先手必胜,反之就是先手必败
那么我们现在先用双重循环递归枚举一遍0-5000的状态,如果当前状态先手必败,那么我们现在就枚举以当前状态,第一堆和第二堆分别加上k和k的倍数或者k的倍数和k,这个状态一定是先手必胜,那么就反转一下这个状态。
同时我们这道题有一个值得注意的问题就是,使用bool类型的数组来存放,一定不要使用int,bool类型的数组处理问题会更加迅速,否则会TLE
#include<iostream>
using namespace std;
bool sg[5002][5002];
void init(){
for(int i=0;i<=5000;i++){
for(int j=0;j<=5000;j++){
if(!sg[i][j]){
for(int k=1;k+i<=5000;k++){
for(int m=0;j+m*k<=5000;m++){
sg[i+k][j+m*k]=1;
}
}
for(int k=1;k+j<=5000;k++){
for(int m=0;i+m*k<=5000;m++){
sg[i+m*k][j+k]=1;
}
}
}
}
}
}
int main(){
int T;
cin>>T;
init();
while(T--){
int a,b;
scanf("%d %d",&a,&b);
// cin>>a>>b;
if(sg[a][b]){
cout<<"Alice"<<endl;
}else cout<<"Bob"<<endl;
}
}