题意:臭名昭著的Alice和Bob又要玩游戏 :(
游戏规则:每个人有八张卡牌,卡牌的数字可以是0、1、2、3、4,在一个人的回合中,它可以选择自己一张牌,再选择对手一张牌,然后把选中的自己这个牌,替换成两张牌之和%5,对手的牌不变。率先实现八张零牌的人获胜。保证先手的人不会立即获胜,存在平局情况,数据有10W组。
题解:显然这个数据量要爆搜打表O1出答案。此题无非就是一个单纯的有向图博弈,因此需要做的就是想帮法把当前局面压缩起来当作点,然后用局面的转移关系建图连边,然后拓扑地依据SG函数的转移条件(所有出态局面都是先手胜->本局面先手负;存在一个出态局面先手负->本局面先手胜)大爆搜即可。
注意到一个人卡牌的顺序是无意义的,因此可以把一个人的状态用5个数字(每种手牌分别有几个,低位代表小数字)表示。我的处理是用一个5位的10进制数字压缩一个人的局面(虽然可以9进制,但是10进制Debug容易),先dfs把总共495种手牌情况搜出来,然后再495^2组合出每一种局面情况并做离散化对应到1-495^2个点上,然后5^2(枚举两个人牌值)地对每个点建立边(反向)。然后就可以拓扑了。数组范围都是打表打出来的,我没学过数学,不会算 :(
这个破题我写了3h。。。第一次写SG爆搜。。。好多东西写这些着就晕了。。。总之就是各种问题。。。人都写傻了。。。菜啊。。。最后跑了700ms还好还好。。。
Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 500;
int d[maxn*maxn];
map<int,int>id;int idcnt;
map<pair<int,int>,int>id2;int id2cnt;
pair<int,int> status[maxn*maxn];
int ans[maxn*maxn];
int first[maxn*maxn],nxt[1750000],des[1750000],tot;
int W[6];
int T,f;
queue<int>Q;
inline int get(int status,int x_){
return status%W[x_+1]/W[x_];
}
void dfs(int dep,int rest,int val){
if (dep==4){
int temp = val+rest*W[4];
if (!id.count(temp)){
id.insert(make_pair(temp,++idcnt));
}
return;
}
for (int i=0;i<=rest;i++){
dfs(dep+1,rest-i,val+W[dep]*i);
}
}
inline void AE(int id1,int id2){
tot++;
des[tot] =id2;
nxt[tot] = first[id1];
first[id1] = tot;
d[id2]++;
}
void addEdge(int fi,int se,int idd){
for (int i=1;i<=4;i++){
for (int j=1;j<=4;j++){
int f = get(fi,i);
int s = get(se,j);
if (f>0&&s>0){
AE(id2[make_pair(se,fi-W[i]+W[(i+j)%5])],idd);
}
}
}
}
void search(){
for (int i=1;i<=id2cnt;i++){
if (d[i]==0){
if (status[i].first==8){
ans[i] =1;
}else{
ans[i] =-1;
}
Q.push(i);
}
}
while (!Q.empty()){
int q = Q.front();
Q.pop();
if (ans[q]==1){
for (int t = first[q];t;t=nxt[t]){
int v = des[t];
d[v]--;
if (d[v]==0&&ans[v]==0){
ans[v]=-1;
Q.push(v);
}
}
}else{
for (int t = first[q];t;t=nxt[t]){
int v = des[t];
d[v]--;
if (ans[v]==0){
ans[v]=1;
Q.push(v);
}
}
}
}
}
void init(){
W[0]=1;
for (int i=1;i<=5;i++)W[i] =W[i-1]*10;
dfs(0,8,0);
for (pair<int,int>fi :id){
for (pair<int,int>se:id){
id2.insert(make_pair(make_pair(fi.first,se.first),++id2cnt));
status[id2cnt] = make_pair(fi.first,se.first);
}
}
memset(d,0,sizeof d);
for (pair<pair<int,int>,int>e:id2){
addEdge(e.first.first,e.first.second,e.second);
}
search();
}
void solve(){
scanf("%d",&f);
int ast=0,bst=0;
for (int i=0;i<8;i++){
int t;
scanf("%d",&t);
ast+=W[t];
}
for (int i=0;i<8;i++){
int t;
scanf("%d",&t);
bst+=W[t];
}
if (f){
int res = ans[id2[make_pair(bst,ast)]];
if (res==1){
printf("Bob\n");
}else if (res==-1){
printf("Alice\n");
}else{
printf("Deal\n");
}
}else{
int res = ans[id2[make_pair(ast,bst)]];
if (res==1){
printf("Alice\n");
}else if (res==-1){
printf("Bob\n");
}else{
printf("Deal\n");
}
}
}
int main(){
init();
scanf("%d",&T);
while (T--){
solve();
}
return 0;
}