题意:Alice先手,与Bob轮流进行拿石子操作,每次从一堆石子中拿出 k(k>0) 颗石子则从另外一堆拿出 k*s(s>=0) 颗石子。谁无法进行操作谁输掉比赛。
思路:说实话是不怎么知道这个博弈该怎么写的,听说赛中许多人都是打表过的这题(就很绝)。赛后看其他大佬题解才知道这个题其实是可以暴力卡过去的。
我们初始化标记 f[i][j] ==1 表示初始两堆石子为 i和j 时为必赢态,反之为必输态。然后我们枚举 i 和j,再分别枚举 k和s 处理 f[i+k][j+k*s] 和 f[i+k*s][j+k] (因为两堆初始石子互换状态是一致的)。
最后注意下输入输出卡时长即可。
代码实现:
#include<bits/stdc++.h>
using namespace std;
const int N = 5010;
inline void read(int &x){
char t=getchar();
while(!isdigit(t)) t=getchar();
for(x=t^48,t=getchar();isdigit(t);t=getchar()) x=x*10+(t^48);
}
int T = 1, n, m;
bool f[N][N];
int main()
{
for(int i = 0; i <= 5000; i ++){
for(int j = 0; j <= 5000; j ++){
if(!f[i][j]){
for(int k = 1; i+k <= 5000; k ++)
for(int s = 0; j+k*s <= 5000; s ++)
f[i+k][j+k*s] = 1;
for(int k = 1; j+k <= 5000; k ++)
for(int s = 0; i+k*s <= 5000; s ++)
f[i+k*s][j+k] = 1;
}
}
}
read(T);
while(T --){
read(n); read(m);
if(f[n][m]) puts("Alice");
else puts("Bob");
}
return 0;
}