Problem:
Score : 700 points

Problem Statement

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 1

2 2
00
01

Sample Output 1

Alice

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

Sample Input 2

2 2
00
11

Sample Output 2

Bob

There are two strings that Alice can add on the first turn: 01 and 10.
In case she adds 01, if Bob add 10, she will be unable to add a new string.
Also, in case she adds 10, if Bob add 01, she will be unable to add a new string.

Sample Input 3

3 3
0
10
110

Sample Output 3

Alice

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

Sample Input 4

2 1
0
1

Sample Output 4

Bob

Alice is unable to add a new string on the first turn.

Sample Input 5

1 2
11

Sample Output 5

Alice

Sample Input 6

2 3
101
11

Sample Output 6

Bob

Solution in Rust (1.15.1) (judge verdict: Accepted)

#[allow(unused_imports)]
use std::cmp::{max, min, Ordering};
#[allow(unused_imports)]
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
#[allow(unused_imports)]
use std::iter::FromIterator;
#[allow(unused_imports)]
use std::io::stdin;

mod util {
    use std::io::stdin;
    use std::str::FromStr;
    use std::fmt::Debug;

    #[allow(dead_code)]
    pub fn line() -> String {
        let mut line: String = String::new();
        stdin().read_line(&mut line).unwrap();
        line.trim().to_string()
    }

    #[allow(dead_code)]
    pub fn gets<T: FromStr>() -> Vec<T>
    where
        <T as FromStr>::Err: Debug,
    {
        let mut line: String = String::new();
        stdin().read_line(&mut line).unwrap();
        line.split_whitespace()
            .map(|t| t.parse().unwrap())
            .collect()
    }
}

#[allow(unused_macros)]
macro_rules! get {
    ($t:ty) => {
        {
            let mut line: String = String::new();
            stdin().read_line(&mut line).unwrap();
            line.trim().parse::<$t>().unwrap()
        }
    };
    ($($t:ty),*) => {
        {
            let mut line: String = String::new();
            stdin().read_line(&mut line).unwrap();
            let mut iter = line.split_whitespace();
            (
                $(iter.next().unwrap().parse::<$t>().unwrap(),)*
            )
        }
    };
    ($t:ty; $n:expr) => {
        (0..$n).map(|_|
                    get!($t)
                   ).collect::<Vec<_>>()
    };
    ($($t:ty),*; $n:expr) => {
        (0..$n).map(|_|
                    get!($($t),*)
                   ).collect::<Vec<_>>()
    };
    ($t:ty ;;) => {
        {
            let mut line: String = String::new();
            stdin().read_line(&mut line).unwrap();
            line.split_whitespace()
                .map(|t| t.parse::<$t>().unwrap())
                .collect::<Vec<_>>()
        }
    };
}

#[allow(unused_macros)]
macro_rules! debug {
    ($($a:expr),*) => {
        println!(concat!($(stringify!($a), " = {:?}, "),*), $($a),*);
    }
}

struct Trie {
    left: Option<Box<Trie>>,
    right: Option<Box<Trie>>,
}

impl Trie {
    fn new() -> Trie {
        Trie {
            left: None,
            right: None,
        }
    }

    fn add(&mut self, s: &[char]) {
        if s.is_empty() {
        } else if s[0] == '0' {
            if self.left.is_none() {
                self.left = Some(Box::new(Trie::new()));
            }
            self.left.as_mut().unwrap().add(&s[1..]);
        } else {
            if self.right.is_none() {
                self.right = Some(Box::new(Trie::new()));
            }
            self.right.as_mut().unwrap().add(&s[1..]);
        }
    }

    fn tails(&self, depth: usize, res: &mut Vec<bool>) {
        if let Some(ref l) = self.left {
            l.tails(depth + 1, res);
        } else {
            res[depth] = !res[depth];
        }

        if let Some(ref r) = self.right {
            r.tails(depth + 1, res);
        } else {
            res[depth] = !res[depth];
        }
    }
}

fn main() {
    let (n, l) = get!(usize, i64);
    let ss = get!(String; n);

    let mut trie = Trie::new();
    let mut max_len = 0;

    for s in &ss {
        let v = s.chars().collect::<Vec<_>>();
        trie.add(&v);
        max_len = max(max_len, v.len());
    }

    // debug!(trie.tails());
    let mut v = vec![false; max_len + 1];
    trie.tails(0, &mut v);

    if v.iter()
        .enumerate()
        .filter_map(|(i, &b)| if b { Some(i) } else { None })
        .map(|d| l - d as i64)
        .map(|x| x & -x)
        .fold(0, |a, b| a ^ b) == 0
    {
        println!("Bob");
    } else {
        println!("Alice");
    }
}