# ACM | LightOJ - 1344 Aladdin and the Game of Bracelets博弈论SG打表

##### Problem Description

It's said that Aladdin had to solve seven mysteries before getting the Magical Lamp which summons a powerful Genie. Here we are concerned about the fourth mystery.

In the cave, Aladdin was moving forward after passing the pathway of magical stones. He found a door and he was about to open the door, but suddenly a Genie appeared and he addressed himself as the guardian of the door. He challenged Aladdin to play a game and promised that he would let Aladdin go through the door, if Aladdin can defeat the Genie. Aladdin defeated the Genie and continued his journey. However, let's concentrate on the game.

The game was called 'Game of Bracelets'. A bracelet is a linear chain of some pearls of various weights. The rules of the game are:

1. There are n bracelets.
2. Players alternate turns.
3. In each turn, a player has to choose a pearl from any bracelet. Then all the pearls from that bracelet, that were not lighter than the pearl, will be removed. It may create some smaller bracelets or the bracelet will be removed if no pearl is left in the bracelet.
4. The player, who cannot take a pearl in his turn, loses.

For example, two bracelets are: 5-1-7-2-4-5-3 and 2-1-5-3, here the integers denote the weights of the pearls. Suppose a player has chosen the first pearl (weight 5) from the first bracelet. Then all the pearls that are not lighter than 5, will be removed (from first bracelet). So, 5-1-7-2-4-5-3, the red ones will be removed and thus from this bracelet, three new bracelets will be formed, 1, 2-4 and 3. So, in the next turn the other player will have four bracelets: 1, 2-4, 3 and 2-1-5-3. Now if a player chooses the only pearl (weight 3) from the third bracelet, then the bracelet will be removed.

Now you are given the information of the bracelets. Assume that Aladdin plays first, and Aladdin and the Genie both play optimally. Your task is to find the winner.

##### Input

Input starts with an integer T (≤ 50), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 50). Each of the next n lines contains an integer Ki (1 ≤ Ki ≤ 50) followed by Ki integers, denoting the weights of the pearls of the ith (1 ≤ i ≤ n) bracelet. Each weight will lie in the range [1, 105].

##### Output

For each case, print the case number and 'Aladdin' if Aladdin wins. Otherwise print 'Genie'. If Aladdin wins, then print an additional line, denoting the weight of pearls, one of which should be chosen in the first move by Aladdin such that he can win. Each pearl should be denoted by a pair of integers: the first integer is the bracelet number and the second integer is the weight. Sort the pearls first by the bracelet number then by the weight. And same weight in a bracelet should be reported once. Check the samples for exact formatting.

4
2
7 5 1 7 2 4 5 3
4 2 1 5 4
2
2 5 2
2 5 2
1
5 5 2 5 2 5
3
5 5 2 5 2 5
5 7 2 7 3 2
4 5 1 5 4

(2 5)
Case 2: Genie
(1 2)(1 5)
(2 7)(3 1)(3 5)

##### 题解 ##### code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 55;
int sg[maxn][maxn]; // 当前手镯 i-j区间的 sg 值
int arr[maxn][maxn], num[maxn]; // 存储每个手镯的权值，每个手镯有多少个珠子
int sgtmp[maxn]; // 第 i 个手镯的 sg 值
int ret[maxn][maxn];  // 去掉第 i 个手镯的第 j 个珠子后，这个手镯的 sg 值

struct node {
int x, y;
} output[maxn * maxn]; // 存储最后的输出答案

bool operator == (node a, node b) {
return a.x == b.x && arr[a.x][a.y] == arr[b.x][b.y];
}

bool cmp(node a, node b) {
if (a.x == b.x) {
return arr[a.x][a.y] < arr[b.x][b.y];
}
return a.x < b.x;
}

int dfs(int now, int l, int r) { // 查找 sg 值
if (l > r) return 0;
if (l == r) return sg[l][r] = 1; // 只有一颗珠子，直接取走，必赢

if (sg[l][r] != -1) return sg[l][r]; // 已找过

int vis[maxn]; // 不可为全局变量
memset(vis, 0, sizeof(vis));

for (int i = l; i <= r; ++i) { // 挑选下标为i处的珠子
int tmp = 0, last = -1;

// 找到第一颗小于当前权值的珠子
for (int j = l; j <= r; ++j) {
if (arr[now][j] < arr[now][i]) {
last = j; break;
}
}

// last 为 -1时，代表已找不到
for (int j = last + 1; j <= r && last != -1; ++j) {
if (arr[now][j] >= arr[now][i]) {
tmp ^= dfs(now, last, j - 1);
last = -1;
for (int k = j + 1; k <= r; ++k) {
if (arr[now][k] < arr[now][i]) {
last = j = k;
break;
}
}
}
}
// 这个手镯的最后一段没被搜索
if (last != -1) {
tmp ^= dfs(now, last, r);
}
vis[tmp] = 1;
// 记录下来，方便后面输出
if (l == 1 && r == num[now]) ret[now][i] = tmp;
//        if (l == 1 && r == num[now]) {
//            printf("%d %d %d\n", now, i, tmp);
//        }
}

for (int i = 0; ; ++i) {
if (vis[i] == 0) {
sg[l][r] = i;
return i;
}
}
return -1;
}

int main() {
int t, k, ca = 1;
scanf("%d", &t);
while (t--) {
int ans = 0;
scanf("%d", &k);
for (int i = 1; i <= k; ++i) {
memset(sg, -1, sizeof(sg));
scanf("%d", &num[i]);
for (int j = 1; j <= num[i]; ++j) {
scanf("%d", &arr[i][j]);
}
sgtmp[i] = dfs(i, 1, num[i]);
//printf("%d\n", sgtmp[i]);
ans ^= sgtmp[i];
//            for (int i = 1; i <= num[i]; ++i) {
//                for (int j = i; j <= num[i]; ++j) {
//                    printf("%d %d %d\n", i, j, sg[i][j]);
//                }
//            }
}
if (ans == 0) printf("Case %d: Genie\n", ca++);
else {
int cnt = 0;
memset(output, 0, sizeof(output));
for (int i = 1; i <= k; ++i) {
for (int j = 1; j <= num[i]; ++j) {
// 先异或这个手镯的 sg 值，消除原本的影响
// 再异或这个手镯选中第j颗珠子，导致取走一部分珠子后的sg值
if ((ans ^ sgtmp[i] ^ ret[i][j]) == 0) {
//printf("(%d %d)", i, arr[i][j]);
output[cnt++] = {i, j};
}
}
}
// 排序并去重，输出
sort(output, output + cnt, cmp);
cnt = (int)(unique(output, output + cnt) - output);
for (int i = 0; i < cnt; ++i) {
printf("(%d %d)", output[i].x, arr[output[i].x][output[i].y]);
};
printf("\n");
}
}
return 0;
} 