2018 China Collegiate Programming Contest - Guilin Site J. stone game

J. Stone Game

time limit per test

1 second

memory limit per test

256 megabytes

Alice and Bob are always playing game! The game today is about taking out stone from the stone piles in turn.

There are n piles of stones, and the i-th pile contains A[i] stones.

As the number of stones in each pile differs from its neighbor’s, they determine to take out exactly one stone from one of them in one turn without breaking that property. Alice goes first.

The player who cannot take stone will lose the game.

Now you have to determine the winner given n numbers representing the piles, if they both play optimally.

You should notice that even a pile of 0 stone is still regarded as a pile!

Input

The first line of input file contains an integer T ( 1 ≤ T ≤ 100 ) (1\le T\le 100) (1T100), describing the number of test cases.

Then there are 2 \times T lines, with every two lines representing a test case.

The first line of each test case contains only one integer n ( 1 ≤ n ≤ 1 0 5 ) (1\le n\le 10^5) (1n105) as described above.

The second line of that contains exactly n numbers, representing the number of stone(s) in a pile in order. All these numbers are ranging in [ 0 , 1 0 9 ] [0,10^9] [0,109].

It is guaranteed that the sum of n in all cases does not exceed 1 0 6 10^6 106.

Output

You should output exactly T lines.

For each test case, print Case d: (d represents the order of the test case) first, then print the name of winner, Alice or Bob.

Example

input

Copy

2
2
1 3
3
1 3 1

output

Copy

Case 1: Alice
Case 2: Bob

Note

Sample 1:

There is a possible stone-taking sequence: ( 1 , 3 ) → ( 1 , 2 ) → ( 0 , 2 ) → ( 0 , 1 ) (1,3)\rightarrow(1,2)\rightarrow(0,2)\rightarrow(0,1) (1,3)(1,2)(0,2)(0,1)

Here is an invalid sequence: ( 1 , 3 ) → ( 1 , 2 ) → ( 1 , 1 ) → ( 0 , 1 ) (1,3)\rightarrow(1,2)\rightarrow(1,1)\rightarrow(0,1) (1,3)(1,2)(1,1)(0,1). Though it has the same result as the first sequence, it breaks that property “the number of stones in each pile differs from its neighbor’s”.

博弈论+拓扑排序

首先要找规律,从两堆石子开始尝试,发现取奇数个石子的时候,Alice赢,取偶数个石子的,Bob赢。

比如3 1

最后的情况是1 0,取了3个石子,那么一定是Alice赢。

比如4 1

最后的情况还是1 0,取4个石子,那么一定是Bob赢。

事实上和石子的总数大小没什么关系,只要判断奇偶性即可。取完两个石堆之后,就尝试3个以上的。

比如1 3 1

最后情况是0 1 0,取4个石子,还是Bob赢

那么我们可以看出,只要确定了最终状态,然后再判断取石子的奇偶性,就能得出答案。

比如5 4 8 9 7 3 6

最后的状态就是 1 0 1 2 1 0 1

因此我们可以把原数组看成一个DAG,小的数指向大的数,然后通过拓扑排序,一次一次递增,得到最终序列.

#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
typedef long long ll;
using namespace std;
#define N 100005
int t, cnt;
ll sum = 0;
int a[N], in[N], f[N];
vector<int> edge[N];
int main() {
    cin.tie(0);
    ios::sync_with_stdio(0);
    int n;
    cin >> n;
    while (n--) {
        // scanf("%d", &t);
        cin >> t;
        for (int i = 1; i <= t; i++) {
            // scanf("%d", &a[i]);
            cin >> a[i];
            sum += a[i];
        }
        a[0] = a[t + 1] = 1e9 + 1;
        for (int i = 2; i <= t; i++) {
            if (a[i] > a[i - 1]) {  // a[i-1]->a[i]
                // cout << a[i] << ' ' << a[i - 1] << ' ';
                edge[i - 1].push_back(i);
                in[i]++;
            }
            if (a[i] < a[i - 1]) {  // a[i]->a[i-1]
                // cout << a[i] << ' ' << a[i - 1] << ' ';
                edge[i].push_back(i - 1);
                in[i - 1]++;
            }
        }
        //---------------------------------------
        queue<int> Q;
        for (int i = 1; i <= t; i++) {
            if (in[i] == 0) {
                Q.push(i);
            }
        }
        while (!Q.empty()) {
            int top = Q.front();
            Q.pop();
            for (int i = 0; i < edge[top].size(); i++) {
                int now = edge[top][i];
                f[now] = max(f[now], f[top] + 1);
                if (--in[now] == 0) {
                    Q.push(now);
                }
            }
        }
        //-------------------------------
        for (int i = 1; i <= t; i++) {
            sum -= f[i];
        }
        cnt++;
        if (sum % 2 == 1) {
            // printf("Case %d: Alice\n", cnt);
            cout << "Case " << cnt << ": "
                 << "Alice" << '\n';
        } else {
            // printf("Case %d: Bob\n", cnt);
            cout << "Case " << cnt << ": "
                 << "Bob" << '\n';
        }
        for (int i = 1; i <= t; i++) {
            edge[i].clear();
            f[i] = 0;
            in[i] = 0;
        }
        sum = 0;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值