AtCoder Regular Contest 087 - Prefix-free Game

For strings s and t, we will say that s and t are prefix-free when neither is a prefix of the other.
Let L be a positive integer. A set of strings S is a good string set when the following conditions hold true:
 - Each string in S has a length between 1 and L (inclusive) and consists of the characters 0 and 1.
 - Any two distinct strings in S are prefix-free.
We have a good string set S = \{ s_1, s_2, ..., s_N \}. Alice and Bob will play a game against each other. They will alternately perform the following operation, starting from Alice:
 - Add a new string to S. After addition, S must still be a good string set.
The first player who becomes unable to perform the operation loses the game. Determine the winner of the game when both players play optimally.

-----Constraints-----
 - 1 \leq N \leq 10^5
 - 1 \leq L \leq 10^{18}
 - s_1, s_2, ..., s_N are all distinct.
 - { s_1, s_2, ..., s_N } is a good string set.
 - |s_1| + |s_2| + ... + |s_N| \leq 10^5

-----Input-----
Input is given from Standard Input in the following format:
N L
s_1
s_2
:
s_N

-----Output-----
If Alice will win, print Alice; if Bob will win, print Bob.

-----Sample Input-----
2 2
00
01

-----Sample Output-----
Alice

If Alice adds 1, Bob will be unable to add a new string.

Difficulty: HARD

Starter code:

Solutions:
import sys
readline = sys.stdin.readline

class Node:

	def __init__(self, sigma, depth):
		self.end = False
		self.child = [None] * sigma
		self.depth = depth

	def __setitem__(self, i, x):
		self.child[i] = x

	def __getitem__(self, i):
		return self.child[i]
sigma = 2
root = Node(sigma, 0)

def add_trie(S):
	vn = root
	for cs in S:
		if vn[cs] is None:
			vn[cs] = Node(sigma, vn.depth + 1)
		vn = vn[cs]
	vn.end = True
ans = 0
(N, L) = map(int, readline().split())
for _ in range(N):
	S = list(map(int, readline().strip()))
	add_trie(S)
cnt = 0
stack = [root]
while stack:
	vn = stack.pop()
	for i in range(2):
		if vn[i] is None:
			r = L - vn.depth
			cnt ^= -r & r
		else:
			stack.append(vn[i])
print('Alice' if cnt else 'Bob')


from collections import defaultdict

def solve(l, ss):
	xor = 0
	for d in range(min(ss), l + 1):
		sl = ss[d]
		sl.sort()
		while sl:
			s = sl.pop()
			ps = s[:-1]
			ss[d + 1].append(ps)
			if s[-1] == '1' and sl and (sl[-1][:-1] == ps):
				sl.pop()
			else:
				xor ^= d & -d
		del ss[d]
	return xor
(n, l) = list(map(int, input().split()))
ss = defaultdict(list)
for s in (input() for _ in range(n)):
	ss[l - len(s) + 1].append(s)
print('Alice' if solve(l, ss) else 'Bob')


(n, l) = map(int, input().split())
ls = [input() for i in range(n)]
sm = sum([len(s) for s in ls])
ls.sort()
num = [0] * (sm + 1)
for i in range(n):
	if i == 0:
		for j in range(len(ls[i])):
			num[j + 1] = 1
	else:
		x = ls[i]
		p = ls[i - 1]
		cnt = 0
		while cnt < min(len(x), len(p)):
			if x[cnt] == p[cnt]:
				cnt += 1
			else:
				break
		num[cnt + 1] -= 1
		for j in range(cnt + 2, len(x) + 1):
			num[j] += 1
ans = 0

def d2(x):
	if x == 0:
		return 0
	cnt = 0
	while x % 2 == 0:
		cnt += 1
		x //= 2
	return 2 ** cnt
for i in range(sm + 1):
	ans ^= d2(l + 1 - i) * (num[i] % 2)
if ans:
	print('Alice')
else:
	print('Bob')


import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 6)
from collections import deque
(N, M) = map(int, input().split())
words = [deque(input().rstrip()) for _ in range(N)]

def G_small():
	G = [0] * 100
	G_cum = [0] * 100
	G[0] = 1
	G_cum[0] = 1
	for n in range(1, 100):
		can_make = set((G_cum[n - 1] ^ G_cum[x] for x in range(n))) | set([G_cum[n - 1]])
		rest = set(range(n + 10)) - can_make
		G[n] = min(rest)
		G_cum[n] = G_cum[n - 1] ^ G[n]
	return G

def G(n):
	n += 1
	x = 1
	while not n & 1:
		n >>= 1
		x <<= 1
	return x

def calc_grandy(words, L):
	if not words:
		return G(L)
	if len(words) == 1 and words[0] == deque():
		return 0
	words_0 = []
	words_1 = []
	for word in words:
		first = word.popleft()
		if first == '0':
			words_0.append(word)
		else:
			words_1.append(word)
	return calc_grandy(words_0, L - 1) ^ calc_grandy(words_1, L - 1)
g = calc_grandy(words, M)
answer = 'Alice' if g != 0 else 'Bob'
print(answer)


def main():
	(N, L) = map(int, input().split())
	keys = []
	grundy_num = 0
	if N == 1:
		print('Alice')
		exit()
	for i in range(N):
		s = input()
		while len(s) > 0:
			if s[-1] == '1' and s[:-1] + '0' in keys:
				keys.remove(s[:-1] + '0')
				s = s[:-1]
			elif s[-1] == '0' and s[:-1] + '1' in keys:
				keys.remove(s[:-1] + '1')
				s = s[:-1]
			else:
				if s != '':
					keys.append(s)
				break
	if len(keys):
		keys = sorted(keys, key=len, reverse=True)
		grundy_list = []
		while len(keys):
			j = keys[0]
			keys.remove(j)
			temp_s = list(reversed(bin(L - len(j) + 1)))
			grundy_list.append(1 << temp_s.index('1'))
			if j[:-1] != '':
				keys.append(j[:-1])
			j = j[:-1]
			while len(j) > 0:
				if j[-1] == '1' and j[:-1] + '0' in keys:
					keys.remove(j[:-1] + '0')
					keys.remove(j)
					j = j[:-1]
					if j != '':
						keys.append(j)
				elif j[-1] == '0' and j[:-1] + '1' in keys:
					keys.remove(j[:-1] + '1')
					keys.remove(j)
					j = j[:-1]
					if j != '':
						keys.append(j)
				else:
					break
			keys = sorted(keys, key=len, reverse=True)
		grundy_num = grundy_list[0]
		for i in range(1, len(grundy_list)):
			grundy_num = grundy_num ^ grundy_list[i]
	print('Bob' if grundy_num == 0 else 'Alice')
main()


from functools import cmp_to_key

def f(s, t):
	m = min(len(s), len(t))
	if s[:m] > t[:m]:
		return 1
	elif s[:m] < t[:m]:
		return -1
	elif len(s) > len(t):
		return -1
	else:
		return 1

def ms(s, t):
	i = 0
	for (c1, c2) in zip(s, t):
		if c1 != c2:
			return i
		i += 1
	return i

def xxor(x):
	if x & 3 == 0:
		return x
	if x & 3 == 1:
		return 1
	if x & 3 == 2:
		return x + 1
	if x & 3 == 3:
		return 0

def gray(x):
	return x ^ x // 2
(n, l) = list(map(int, input().split()))
s = [input() for _ in range(n)]
s.sort(key=cmp_to_key(f))
g = gray(l) ^ gray(l - len(s[0]))
for i in range(n - 1):
	b = ms(s[i], s[i + 1]) + 1
	g ^= gray(l - b + 1) ^ gray(l - b)
	t = len(s[i + 1]) - b
	g ^= gray(l - b) ^ gray(l - b - t)
if g == 0:
	print('Bob')
else:
	print('Alice')


def main():
	import sys
	input = sys.stdin.readline

	class TreiNode:

		def __init__(self, char_num, depth):
			self.end = False
			self.child = [None] * char_num
			self.depth = depth

		def __setitem__(self, i, x):
			self.child[i] = x

		def __getitem__(self, i):
			return self.child[i]

	class Trei:

		def __init__(self, char_num):
			self.root = TreiNode(char_num, 0)
			self.char_num = char_num

		def add(self, S):
			v = self.root
			for s in S:
				if v[s] is None:
					v[s] = TreiNode(self.char_num, v.depth + 1)
				v = v[s]
			v.end = True

		def exist(self, S):
			v = self.root
			for s in S:
				if v[s] is None:
					return False
				v = v[s]
			if v.end:
				return True
			else:
				return False
	(N, L) = map(int, input().split())
	T = Trei(2)
	for _ in range(N):
		S = input().rstrip('\n')
		S = [int(s) for s in S]
		T.add(S)
	g = 0
	st = [T.root]
	while st:
		v = st.pop()
		for i in range(2):
			if v[i] is None:
				d = L - v.depth
				g ^= d & -d
			else:
				st.append(v[i])
	if g:
		print('Alice')
	else:
		print('Bob')
main()


from collections import defaultdict

def solve(n, l, nums):
	xor = 0
	if n == 1:
		for i in range(min(nums), l + 1):
			xor ^= i & -i
		return xor
	for i in range(min(nums), l + 1):
		ni = nums[i]
		for k in ni:
			if k ^ 1 not in ni:
				xor ^= i & -i
			nums[i + 1].add(k // 2)
		del nums[i]
	return xor
(n, l) = list(map(int, input().split()))
nums = defaultdict(set)
for s in (input() for _ in range(n)):
	nums[l - len(s) + 1].add(int(s, 2) + (1 << len(s)))
print('Alice' if solve(n, l, nums) else 'Bob')


import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 9)
from collections import deque

class Node:

	def __init__(self, depth):
		self.depth = depth
		self.left = None
		self.right = None

def insert(node, s):
	n = node
	for i in range(len(s)):
		t = s[i]
		if t == '0':
			if n.left is None:
				n.left = Node(i + 1)
			n = n.left
		else:
			if n.right is None:
				n.right = Node(i + 1)
			n = n.right

class Trie:

	def __init__(self):
		self.root = Node(0)

	def insert(self, s: str):
		insert(self.root, s)
(n, l) = map(int, input().split())
S = [input().strip() for _ in range(n)]
trie = Trie()
for s in S:
	trie.insert(s)
Data = []
q = deque([trie.root])

def dfs(node):
	if node.right is None and node.left is None:
		return
	if node.right is None or node.left is None:
		Data.append(l - node.depth)
	if node.right:
		q.append(node.right)
	if node.left:
		q.append(node.left)
while q:
	dfs(q.popleft())
xor = 0

def Grundy(n):
	ret = 1
	while n % 2 == 0:
		n //= 2
		ret *= 2
	return ret
for i in Data:
	xor ^= Grundy(i)
print('Alice' if xor else 'Bob')


import sys
sys.setrecursionlimit(10 ** 6)

def input():
	return sys.stdin.readline()[:-1]
(n, l) = list(map(int, input().split()))
ss = [list(input())[::-1] for _ in range(n)]

def addTree(tree, sentence):
	if not sentence:
		return None
	if sentence[-1] not in tree:
		tree[sentence[-1]] = {}
	p = sentence.pop()
	tree[p] = addTree(tree[p], sentence)
	return tree

def createTree(sentences):
	tree = {}
	for sentence in sentences:
		tree = addTree(tree, sentence)
	return tree
tree = createTree(ss)
grundy = 0

def dfs(cur, level):
	nonlocal grundy
	if cur is None:
		return
	elif len(cur) == 1:
		grundy ^= l - level & -l + level
	for k in list(cur.keys()):
		dfs(cur[k], level + 1)
	return
dfs(tree, 0)
if grundy == 0:
	print('Bob')
else:
	print('Alice')


def main():
	import sys
	from collections import defaultdict
	input = sys.stdin.readline
	mod = 10 ** 10 + 7
	mod2 = 10 ** 10 + 9
	mod3 = 998244353
	(N, L) = map(int, input().split())
	dic = defaultdict(int)
	dic2 = defaultdict(int)
	dic3 = defaultdict(int)
	h_list = []
	h2_list = []
	h3_list = []
	pair = {}
	pair2 = {}
	pair3 = {}
	M = 0
	for _ in range(N):
		s = input().rstrip('\n')
		h = 0
		h2 = 0
		h3 = 0
		for i in range(len(s)):
			M += 1
			h = (h * 1007 + int(s[i]) + 1) % mod
			pair[h] = (h + 1) % mod if s[i] == '0' else (h - 1) % mod
			h2 = (h2 * 2009 + int(s[i]) + 1) % mod2
			pair2[h2] = (h2 + 1) % mod2 if s[i] == '0' else (h2 - 1) % mod2
			h3 = (h3 * 3001 + int(s[i]) + 1) % mod3
			pair3[h3] = (h3 + 1) % mod3 if s[i] == '0' else (h3 - 1) % mod3
			dic[h] = i + 1
			dic2[h2] = i + 1
			dic[h3] = i + 1
			h_list.append(h)
			h2_list.append(h2)
			h3_list.append(h3)
	g = 0
	seen = defaultdict(int)
	seen2 = defaultdict(int)
	seen3 = defaultdict(int)
	for i in range(M):
		(s, s2, s3) = (h_list[i], h2_list[i], h3_list[i])
		if seen[s] and seen2[s2] and seen3[s3]:
			continue
		t = pair[s]
		t2 = pair2[s2]
		t3 = pair3[s3]
		if dic[t] == 0 or dic2[t2] == 0 or dic3[t3] == 0:
			p = [dic[s], dic2[s2], dic3[s3]]
			p.sort()
			tmp = L - p[1] + 1
			cnt = 0
			while tmp % 2 == 0:
				tmp //= 2
				cnt += 1
			g ^= 2 ** cnt
		seen[s] = 1
		seen2[s2] = 1
		seen3[s3] = 1
	if g:
		print('Alice')
	else:
		print('Bob')
main()


import sys
(N, L) = map(int, input().split())
sys.setrecursionlimit(200000)

class Node:

	def __init__(self, depth=0):
		self.parent = None
		self.children = {}
		self.depth = depth

	def add(self, n):
		self.children[n] = Node(self.depth + 1)

	def has(self, n):
		return n in self.children
t = Node()
for i in range(N):
	s = input()
	nt = t
	for c in s:
		if not nt.has(c):
			nt.add(c)
		nt = nt.children[c]

def solve(node):
	global N, L
	ans = 0
	f = lambda d: L - d & -(L - d)
	if node.has('0'):
		ans ^= solve(node.children['0'])
	else:
		ans ^= f(node.depth)
	if node.has('1'):
		ans ^= solve(node.children['1'])
	else:
		ans ^= f(node.depth)
	return ans
ans = solve(t)
if ans == 0:
	print('Bob')
else:
	print('Alice')


import sys
readline = sys.stdin.readline
read = sys.stdin.read
(_, L) = list(map(int, readline().split()))
s = read().split()

def grundy(x):
	if x == 0:
		return 0
	r = 1
	while x % 2 == 0:
		x //= 2
		r *= 2
	return r
g = 0
st = [(s, 0)]
while st:
	(a, idx) = st.pop()
	a0 = []
	a1 = []
	for i in a:
		if len(i) <= idx:
			continue
		if i[idx] == '0':
			a0.append(i)
		else:
			a1.append(i)
	if a0 and (not a1) or (a1 and (not a0)):
		g ^= grundy(L - idx)
	if a0:
		st.append((a0, idx + 1))
	if a1:
		st.append((a1, idx + 1))
if g:
	print('Alice')
else:
	print('Bob')


import sys
sys.setrecursionlimit(100000)

def dfs(cur, dep=0):
	if cur == -1:
		x = l - dep
		return x & -x
	return dfs(trie[cur][0], dep + 1) ^ dfs(trie[cur][1], dep + 1)
(n, l) = map(int, input().split())
trie = [[-1, -1] for _ in range(100001)]
idx = 1
for s in (input() for _ in range(n)):
	cur = 0
	for c in map(int, s):
		if trie[cur][c] == -1:
			trie[cur][c] = idx
			idx += 1
		cur = trie[cur][c]
xor = dfs(trie[0][0]) ^ dfs(trie[0][1])
print('Alice' if xor else 'Bob')


import sys
sys.setrecursionlimit(1000000)

def getGrundyNumber(x):
	ans = 1
	while x % (ans * 2) == 0:
		ans *= 2
	return ans

def dfs(iT, Hgt):
	num = 0
	for c in Trie[iT]:
		if c != -1:
			dfs(c, Hgt - 1)
			num += 1
	if num == 1:
		Hgts[Hgt - 1] = Hgts.get(Hgt - 1, 0) + 1
(N, L) = map(int, input().split())
Ss = [input() for i in range(N)]
Trie = [[-1, -1]]
for S in Ss:
	iT = 0
	for c in map(int, S):
		if Trie[iT][c] == -1:
			Trie += [[-1, -1]]
			Trie[iT][c] = len(Trie) - 1
		iT = Trie[iT][c]
Hgts = {}
dfs(0, L + 1)
ans = 0
for (Hgt, num) in Hgts.items():
	if num % 2:
		ans ^= getGrundyNumber(Hgt)
if ans:
	print('Alice')
else:
	print('Bob')


def getGrundyNumber(x):
	ans = 1
	while x % (ans * 2) == 0:
		ans *= 2
	return ans
(N, L) = map(int, input().split())
Ss = [input() for i in range(N)]
Trie = [[-1, -1]]
for S in Ss:
	iT = 0
	for c in map(int, S):
		if Trie[iT][c] == -1:
			Trie += [[-1, -1]]
			Trie[iT][c] = len(Trie) - 1
		iT = Trie[iT][c]
Hgts = {}
stack = [(0, L + 1)]
while stack:
	(iT, Hgt) = stack.pop()
	num = 0
	for c in Trie[iT]:
		if c != -1:
			stack.append((c, Hgt - 1))
			num += 1
	if num == 1:
		Hgts[Hgt - 1] = Hgts.get(Hgt - 1, 0) + 1
ans = 0
for (Hgt, num) in Hgts.items():
	if num % 2:
		ans ^= getGrundyNumber(Hgt)
if ans:
	print('Alice')
else:
	print('Bob')


def getGrundyNumber(x):
	ans = 1
	while x % (ans * 2) == 0:
		ans *= 2
	return ans
(N, L) = map(int, input().split())
Ss = [input() for i in range(N)]
Ss.sort()
Hgts = {L: 2}
prev = '_'
for S in Ss:
	for (iS, (a, b)) in enumerate(zip(prev, S)):
		if a != b:
			Hgts[L - iS] -= 1
			for h in range(L - len(S) + 1, L - iS):
				Hgts[h] = Hgts.get(h, 0) + 1
			break
	prev = S
ans = 0
for (Hgt, num) in Hgts.items():
	if num % 2:
		ans ^= getGrundyNumber(Hgt)
if ans:
	print('Alice')
else:
	print('Bob')


def tp_z(now, nd):
	if z_child[now] == None:
		ret = len(z_child)
		z_child[now] = ret
		z_child.append(None)
		o_child.append(None)
		dep.append(nd + 1)
	else:
		ret = z_child[now]
	return ret

def tp_o(now, nd):
	if o_child[now] == None:
		ret = len(z_child)
		o_child[now] = ret
		z_child.append(None)
		o_child.append(None)
		dep.append(nd + 1)
	else:
		ret = o_child[now]
	return ret

def grundy(nd):
	if nd == 0:
		return 0
	for i in range(64):
		if nd % 2 ** i != 0:
			return 2 ** (i - 1)
(N, L) = map(int, input().split())
z_child = [None]
o_child = [None]
dep = [0]
for loop in range(N):
	now = 0
	s = input()
	for i in s:
		if i == '0':
			now = tp_z(now, dep[now])
		else:
			now = tp_o(now, dep[now])
ans = 0
for i in range(len(z_child)):
	if z_child[i] == None:
		ans ^= grundy(L - dep[i])
	if o_child[i] == None:
		ans ^= grundy(L - dep[i])
if ans == 0:
	print('Bob')
else:
	print('Alice')


from collections import deque

class Node:

	def __init__(self, x):
		self.data = int(x)
		self.left = None
		self.right = None

def insert(node, x):
	ima = node
	for i in range(len(x)):
		y = x[i]
		if y == '1':
			if ima.right is None:
				ima.right = Node(i + 1)
			ima = ima.right
		else:
			if ima.left is None:
				ima.left = Node(i + 1)
			ima = ima.left

class Trie:

	def __init__(self):
		self.root = Node(0)

	def insert(self, x):
		insert(self.root, x)
(n, l) = map(int, input().split())
s = [input() for i in range(n)]
trie = Trie()
for i in s:
	trie.insert(i)
data = []
que = deque([trie.root])

def dfs(node):
	if node.right is None and node.left is None:
		return 0
	if node.right is None or node.left is None:
		if l - node.data:
			data.append(l - node.data)
	if node.right:
		que.append(node.right)
	if node.left:
		que.append(node.left)
while que:
	dfs(que.popleft())
xor = 0

def nimber(n):
	x = 1
	while n % 2 == 0:
		n //= 2
		x *= 2
	return x
for i in data:
	xor ^= nimber(i)
print('Alice' if xor else 'Bob')


import random
(N, L) = list(map(int, input().split()))
M = 2 * 10 ** 5 + 1
sets = [set() for _ in range(M + 1)]
MOD = 282525872416376072492401
r_max = 10 ** 6
inv_t = [0, 1]
for i in range(2, r_max + 1):
	inv_t.append(inv_t[MOD % i] * (MOD - MOD // i) % MOD)
r = random.randint(10 ** 5, r_max)
rinv = inv_t[r]

def has(s):
	ans = 0
	i = 0
	for x in s:
		ans *= r
		ans += int(x) + (i + 1) ** 2
		ans %= MOD
		i += 1
	return ans % MOD

def tract(x, s, l):
	return (x - int(s) - l ** 2) * rinv % MOD
strs = []
dic = {}
ct = 0
for i in range(N):
	s = input()
	strs.append(s)
	sets[len(s)].add(has(s))
	if has(s) in dic:
		print(('warning!!', s))
		ct += 1
	dic[has(s)] = i
free_num = [0 for _ in range(M + 1)]
for l in range(M, 0, -1):
	while len(sets[l]) > 0:
		x = sets[l].pop()
		last = strs[dic[x]][l - 1]
		x_p = tract(x, last, l)
		sets[l - 1].add(x_p)
		dic[x_p] = dic[x]
		x_anti = (x_p * r + 1 - int(last) + l ** 2) % MOD
		if x_anti in sets[l]:
			sets[l].remove(x_anti)
		else:
			free_num[l] += 1
Grandy = 0
for i in range(M + 1):
	G_base = L - i + 1
	if free_num[i] % 2 == 1:
		Grandy ^= G_base & -G_base
print('Alice' if Grandy > 0 else 'Bob')


import sys
from collections import deque
sys.setrecursionlimit(10000)
INF = float('inf')
(N, L) = list(map(int, input().split()))
S = set()
for _ in range(N):
	S.add(input())

def grundy(size):
	i = 1
	while (L - size + 1) % i == 0:
		i *= 2
	return i // 2
trie = {}
for s in S:
	t = trie
	for c in s:
		if c not in t:
			t[c] = {}
		t = t[c]
ok_size_list = []
children = deque()
children.append((trie, 0))
while len(children) > 0:
	(node, size) = children.popleft()
	if len(node) == 1:
		ok_size_list.append(size + 1)
	for (c, child) in node.items():
		children.append((child, size + 1))
g = 0
for size in ok_size_list:
	g ^= grundy(size)
if g != 0:
	print('Alice')
else:
	print('Bob')


import sys
sys.setrecursionlimit(2 * 10 ** 5)

class TrieNode:

	def __init__(self, char):
		self.char = char
		self.nextnode = dict()
		self.is_indict = False

class Trie:

	def __init__(self, charset):
		self.charset = charset
		self.root = TrieNode('')

	def add(self, a_str):
		node = self.root
		for (i, char) in enumerate(a_str):
			if char not in node.nextnode:
				node.nextnode[char] = TrieNode(char)
			node = node.nextnode[char]
			if i == len(a_str) - 1:
				node.is_indict = True

	def dfs(self, node, dep):
		(ret, cnt) = (0, 0)
		if node.is_indict:
			return 0
		for s in '01':
			if s not in node.nextnode:
				cnt += 1
			else:
				ret ^= self.dfs(node.nextnode[s], dep + 1)
		height = L - dep
		if cnt % 2:
			power2 = 0
			while height > 0 and height % 2 == 0:
				power2 += 1
				height //= 2
			ret ^= 2 ** power2
		return ret

	def debug_output(self, node, now):
		print(node.char, list(node.nextnode.items()), node.is_indict, now)
		if node.is_indict:
			print(now)
		for n in node.nextnode.values():
			self.debug_output(n, now + n.char)
(N, L) = map(int, input().split())
T = Trie('01')
for _ in range(N):
	T.add(input())
print('Alice' if T.dfs(T.root, 0) else 'Bob')


(N, L) = map(int, input().split())
make = lambda : [None, None, 0]
root = make()

def construct(s):
	n = root
	for i in s:
		if n[i] is None:
			n[i] = n = make()
		else:
			n = n[i]
	n[2] = 1
for i in range(N):
	s = map(int, input())
	construct(s)
caps = {}
st = [(root, 0, 0)]
while st:
	(n, i, l) = st.pop()
	if i:
		if n[1] is None:
			caps[L - l] = caps.get(L - l, 0) + 1
		elif not n[1][2]:
			st.append((n[1], 0, l + 1))
	else:
		st.append((n, 1, l))
		if n[0] is None:
			caps[L - l] = caps.get(L - l, 0) + 1
		elif not n[0][2]:
			st.append((n[0], 0, l + 1))
ans = 0
for v in caps:
	k = caps[v]
	if k % 2 == 0:
		continue
	v -= 1
	r = 1
	while v % 4 == 3:
		v //= 4
		r *= 4
	if v % 4 == 1:
		ans ^= r * 2
	else:
		ans ^= r
print('Alice' if ans else 'Bob')


import os
import sys
if os.getenv('LOCAL'):
	sys.stdin = open('_in.txt', 'r')
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
IINF = 10 ** 18
MOD = 10 ** 9 + 7

def make_trie(str_set):
	trie = {}
	for s in str_set:
		node = trie
		for c in s:
			if c not in node:
				node[c] = {}
			node = node[c]
	return trie
(N, L) = list(map(int, sys.stdin.buffer.readline().split()))
S = [sys.stdin.buffer.readline().decode().rstrip() for _ in range(N)]
trie = make_trie(S)

def grundy(i):
	ret = 1
	while L - i + 1 & ret == 0:
		ret <<= 1
	return ret
g = 0
stack = [(trie, 0)]
while stack:
	(nodes, depth) = stack.pop()
	if depth < L and len(nodes) == 1:
		g ^= grundy(depth + 1)
	for children in nodes.values():
		stack.append((children, depth + 1))
if g == 0:
	print('Bob')
else:
	print('Alice')


class Node:

	def __init__(self, size, avail):
		self.end = False
		self.nxt = [None] * size
		self.avail = avail

	def __setitem__(self, i, x):
		self.nxt[i] = x

	def __getitem__(self, i):
		return self.nxt[i]

def makeTrie(strs, size):
	root = Node(size, l)
	for s in strs:
		n = root
		for c in s:
			i = int(c)
			if not n[i]:
				n[i] = Node(size, n.avail - 1)
			n = n[i]
		n.end = True
	return root

def nimber(n):
	x = 1
	while n % 2 == 0:
		n //= 2
		x *= 2
	return x
input = __import__('sys').stdin.readline
(n, l) = map(int, input().split())
strs = [input().rstrip() for i in range(n)]
T = makeTrie(strs, 2)
ans = 0
stack = [T]
while stack:
	n = stack.pop()
	for i in (0, 1):
		if not n[i]:
			ans ^= nimber(n.avail)
		elif not n[i].end:
			stack.append(n[i])
print('Alice' if ans else 'Bob')


class Node:

	def __init__(self):
		self.lt = None
		self.rt = None
		self.dep = None

class Trie:

	def __init__(self):
		self.root = Node()
		self.root.dep = 0

	def add(self, string):
		node = self.root
		for s in string:
			if s == '0':
				if node.lt is None:
					node.lt = Node()
					node.lt.dep = node.dep + 1
				node = node.lt
			else:
				if node.rt is None:
					node.rt = Node()
					node.rt.dep = node.dep + 1
				node = node.rt
(N, L) = map(int, input().split())
trie = Trie()
for _ in range(N):
	s = input()
	trie.add(s)
subgame = []
stack = [trie.root]
while stack:
	node = stack.pop()
	if node.lt is None and node.rt is None:
		continue
	elif node.rt is None:
		stack.append(node.lt)
		subgame.append(L - node.dep)
	elif node.lt is None:
		stack.append(node.rt)
		subgame.append(L - node.dep)
	else:
		stack.append(node.lt)
		stack.append(node.rt)

def grundy(n):
	if n == 0:
		return 0
	if n % 2 == 1:
		return 1
	if n == 2 ** (n.bit_length() - 1):
		return n
	return grundy(n - 2 ** (n.bit_length() - 1))
g = 0
for l in subgame:
	g ^= grundy(l)
print('Alice' if g != 0 else 'Bob')


from collections import defaultdict
import sys
sys.setrecursionlimit(10 ** 6)
input = sys.stdin.readline
int1 = lambda x: int(x) - 1
p2D = lambda x: print(*x, sep='\n')

def main():
	(n, l) = map(int, input().split())
	ss = [input()[:-1] for _ in range(n)] + ['$']
	ss.sort()
	cnt_tree = defaultdict(int)
	cnt_tree[l] = 2
	for (s0, s1) in zip(ss, ss[1:]):
		for (depth, (c0, c1)) in enumerate(zip(s0, s1)):
			if c0 == c1:
				continue
			cnt_tree[l - depth] -= 1
			for lv in range(l - depth - 1, l - len(s1), -1):
				cnt_tree[lv] += 1
			break
	sum_xor = 0
	for (lv, cnt) in cnt_tree.items():
		if cnt % 2 == 0:
			continue
		sum_xor ^= lv & -lv
	if sum_xor:
		print('Alice')
	else:
		print('Bob')
main()