#include using namespace std; #define ll long long #define rep(i, l, r) for (int i = (int)(l); i < (int)(r); i++) #define all(x) (x).begin(), (x).end() #define siz(x) (int)(x).size() //座標圧縮を行う関数 template vector compress(vector A) { int N = siz(A); vector B = A; sort(B.begin(), B.end()); vector ret(N); rep(i, 0, N) { ret[i] = lower_bound(all(B), A[i]) - B.begin(); } return ret; } struct interval { int l, r; }; int main() { // freopen("in.txt", "r", stdin); // freopen("out1.txt", "w", stdout); //頑張って配列で管理しているので、時間計算量 O(N log N) 空間計算量 O(N log N) int N; cin >> N; vector A(N); for (int i = 0; i < N; i++) cin >> A[i]; //座標圧縮 vector B = compress(A); //短いほうのcntの生成に利用する //高々18個 vector> cnt(20, vector(N, 0)); auto f = [&](auto f, int l, int r, int id, vector& goods) -> int { // cout << l << " " << r << " " << id << endl; if (l == r) return 0; int m = -1; //goodsには0も紛れ込む可能性があるので、排除する。 while(!goods.empty()) { if (cnt[id][B[goods.back()]] == 1) { m = goods.back(); break; } goods.pop_back(); } if (m == -1) return r - l; cnt[id][B[m]]--; //short, long interval sh = {l, m}, lo = {m+1, r}; if (m - l > r - (m + 1)) swap(sh, lo); rep(i, sh.l, sh.r) cnt[id+1][B[i]]++; vector goods_sh; rep(i, sh.l, sh.r) if (cnt[id+1][B[i]]) goods_sh.push_back(i); int result_sh = f(f, sh.l, sh.r, id+1, goods_sh); //再利用するので、必要なくなったら0埋めされた状態に戻しておく rep(i, sh.l, sh.r) cnt[id+1][B[i]]--; //短いほうの区間 [sh.l, sh.r) がなくなった分を cnt, goods に差分更新する rep(i, sh.l, sh.r) cnt[id][B[i]]--; rep(i, sh.l, sh.r) if (cnt[id][B[i]] == 1) goods.push_back(i); int result_lo = f(f, lo.l, lo.r, id, goods); return result_sh + result_lo; }; rep(i, 0, N) cnt[0][B[i]]++; vector goods; rep(i, 0, N) if (cnt[0][B[i]] == 1) goods.push_back(i); // cout << siz(goods) << endl; int ans = f(f, 0, N, 0, goods); // cout << "ans = " << ans << endl; int turn = N - ans; cout << (turn%2? "Alice" : "Bob") << endl; }