#include <stdio.h>
#include <iostream>
#include <cstdio>
#include <algorithm> 
#include <stdio.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <map>
#include <list>
#include <utility>
#include <set>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <numeric>
#include <bitset>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <random>

using namespace std;

static const double EPS = 1e-9;
template<class T> bool INRANGE(T x, T a, T b) { return a <= x&&x <= b; }
template<class T> void amin(T &a, T v) { if (a > v) a = v; }
template<class T> void amax(T &a, T v) { if (a < v) a = v; }
int ROUND(double x) { return (int)(x + 0.5); }
bool ISINT(double x) { return fabs(ROUND(x) - x) <= EPS; }
bool ISEQUAL(double x, double y) { return fabs(x - y) <= EPS*max(1.0, max(fabs(x), fabs(y))); }
double SQSUM(double x, double y) { return x*x + y*y; }
#define PI  (acos(-1))
#define ARRAY_NUM(a) (sizeof(a)/sizeof(a[0])) 
#define NG (-1)
#define BIG ((int)1e9+10)
#define BIGLL ((ll)4e18)
#define SZ(a) ((int)(a).size())
#define SQ(a) ((a)*(a))
typedef unsigned long long ull;
typedef long long ll;


#if 1

class Trie
{
public:
	const static int	MAX_NODES = 1000000+10; // 1M個 * 27 * 4 Byte = 100Mぐらい
	const static char	BASE_C = '0';	// 
	const static int	NUM_CHARS = 2;

	int numNodes = 0;
	int nextNode[NUM_CHARS][MAX_NODES];	// 0は未登録。頂点番号は1からアサインされる。
	bool isWord[MAX_NODES];
	bool isCreated[MAX_NODES];

	Trie()
	{
		memset(nextNode, 0, sizeof(nextNode));	
		memset(isWord, 0, sizeof(isWord));			// 登録した単語があるか
		memset(isCreated, 0, sizeof(isCreated));	// このノードが使われているか（文字単位。木の途中のノードもtrue）
	}

	void insert(const string &s) 
	{
		int v = 0;

		for (int i = 0; i < s.size(); ++i) 
		{
			const int c = s[i] - BASE_C;
			if (!isCreated[nextNode[c][v]])
			{
				nextNode[c][v] = ++numNodes;
				isCreated[numNodes] = true;
			}
			v = nextNode[c][v];
		}
		isWord[v] = true;
	}

	bool search(const string &s) const
	{
		int v = 0;

		for (int i = 0; i < s.size(); ++i) 
		{
			const int c = s[i] - BASE_C;
			if (!isCreated[nextNode[c][v]])
				return false;
			v = nextNode[c][v];
		}
		return isWord[v];
	}

	
	map <int, int> mp;

	void dfs(int v, int depth)
	{
		int numChilds = 0;
		for (int c = 0; c < NUM_CHARS; ++c)
		{
			if (isCreated[nextNode[c][v]])
			{
				numChilds++;
				dfs(nextNode[c][v], depth+1);
			}
		}

		if (numChilds == 1)
		{
			mp[depth] ++;
		}
	}
};





map <ll, int> grundyMemo;

// height 完全二分木の高さ
int grundy(int height)
{
	if (grundyMemo.count(height))
	{
		return grundyMemo[height];
	}

	set <int> s;


	// 次の状態の全てのGrundy数を求めて記録しておく。
	// （次の手で、文字列depth+1を試しているのと同等。）
	// （どこにでもおける二分木なので、文字列の長さにのみ興味がある。）
	for (int depth = 0; depth < height; ++depth)
	{
		int g = 0;

		// 新しくできる、複数の完全二分木。
		for (int h= height-1;h>= height-depth;--h)
		{
			g ^= grundy(h);
		}
		s.insert(g);
	}

	//
	// 例えば次の状態が(0,2,3)のときは、Grundy数は1（4ではない！）
	int res = 0;
	while (s.count(res)) res ++;
	return grundyMemo[height] = res;
}

Trie trie;

int main()
{
	map <ll, int> grundyMemo;

	for (int h = 0; h < 64; h++)
	{
		// 試すのは完全二分木１本ずつ。（複数の完全二分木がある状態はxorで簡単に求められるので、ここで計算するのは無意味。）
		int x = grundy(h);
		// BEGIN CUT HERE
//		cerr << " x=" << x << " h=" << h << endl;
		// END CUT HERE
	}

	int N;
	ll L;
	cin >> N >> L;

	for (int i=0;i<N;++i)
	{
		string s;
		cin >> s;

		trie.insert(s);
	}

	trie.dfs(0, 0);
	ll g = 0;
	for (const auto& a : trie.mp)
	{
		if (a.second & 1)
		{
			ll x = L - a.first;

			if (x > 0)
			{
				ll rightest1 = 0;
				while (x)
				{
					if (x & 1)
					{
						break;
					}

					x /= 2LL;
					rightest1++;
				}

				g ^= 1LL << rightest1;
			}
		}
	}

	if (g == 0)
	{
		cout << "Bob" << endl;
	}
	else
	{
		cout << "Alice" << endl;
	}

	return 0;
}



#elif 1

static bool dp[2][16000+10];
// dp[回転ごとに区切った移動ターン][座標] = いけるか


bool ok( const vector <int>& ud, int goal)
{

	const int S = SZ(ud);
	if (S == 0)
	{
		return goal == 0;
	}

	memset(dp, 0, sizeof(dp));
	const int GETA = 8000+2;

	// dp　
	dp[0][GETA] = true;



	int now;
	int next;
	for (int i=0;i<S;++i)
	{
		now = i % 2;
		next = 1 - now;

		memset(dp[next], 0, sizeof(dp[next]));
		for (int y = -GETA; y <= GETA; y++)
		{
			if (dp[now][y+GETA])
			{
				dp[next][y + GETA + ud[i]] = true;
				dp[next][y + GETA - ud[i]] = true;
			}
		}
	}

	return dp[next][goal + GETA];
}

int main()
{
	string s;

	cin >> s;
	s += 'T';

	int x, y;
	cin >> x >> y;

	vector <int> ud, lr;

	int turn = 0;
	int forward = 0;
	for (int i=0;i<SZ(s);++i)
	{
		if (s[i] == 'T')
		{

			if (turn == 0)
			{
				x -= forward;
			}
			else if (turn % 2 == 1)
			{
				ud.push_back(forward);
			}
			else
			{
				lr.push_back(forward);
			}

			turn++;

			forward = 0;
		}
		else
		{
			forward++;
		}
	}

	if (ok(ud, y) && ok(lr, x))
	{
		printf("Yes\n");
	}
	else
	{
		printf("No\n");
	}

	return 0;






}

#elif 1

int main()
{
	int N;
	scanf("%d", &N);

	map <int, int> mp;
	for (int i = 0; i < N; ++i)
	{
		int tmp;
		scanf("%d", &tmp);

		mp[tmp]++;
	}

	int ans = 0;

	for (const auto& a : mp)
	{
		if (a.second > a.first)
		{
			ans += a.second - a.first;
		}
		else if (a.second < a.first)
		{
			ans += a.second;
		}
	}


	printf("%d\n",ans);

	return 0;

}

#endif



Measured memory_bytes: 18080