Codeforces Round #832 (Div. 2) C. Swap Game 解题报告

原题链接:

Problem - C - Codeforces

题目描述:

Alice and Bob are playing a game on an array aa of nn positive integers. Alice and Bob make alternating moves with Alice going first.

In his/her turn, the player makes the following move:

  • If a1=0a1=0, the player loses the game, otherwise:
  • Player chooses some ii with 2≤i≤n2≤i≤n. Then player decreases the value of a1a1 by 11 and swaps a1a1 with aiai.

Determine the winner of the game if both players play optimally.

Input

The input consists of multiple test cases. The first line contains a single integer tt (1≤t≤2⋅104)(1≤t≤2⋅104)  — the number of test cases. The description of the test cases follows.

The first line of each test case contains a single integer nn (2≤n≤105)(2≤n≤105)  — the length of the array aa.

The second line of each test case contains nn integers a1,a2…ana1,a2…an (1≤ai≤109)(1≤ai≤109)  — the elements of the array aa.

It is guaranteed that sum of nn over all test cases does not exceed 2⋅1052⋅105.

Output

For each test case, if Alice will win the game, output "Alice". Otherwise, output "Bob".

You can output each letter in any case. For example, "alIcE", "Alice", "alice" will all be considered identical.

题目大意:

Alice和Bob玩一个数字游戏,给定n个正整数,两人轮流操作,每个玩家的回合开始时,玩家首先要把a1减一,然后将a1和其他任意一个数字进行交换,然后轮到下一个玩家开始操作。当一个玩家的回合开始时a1如果为负数则该玩家失败。问Alice先手并且两人都使用最优策略的情况下,双方谁会赢。

解题思路:

因为是轮到谁的时候a1=0,那么谁就输。所以两个玩家都会在把a1减1后,尽量把后边最小的数字换到第一位,将其留给下一个玩家。如果最小的那个数就在a1,那么后手的Bob每次操作都会将其换回到a1将其留给Alice,最后一定都是Alice先遇到a1=0,如果不在a1,那么先手的Alice都会将其换回a1将其留给Bob,最后一定都是Bob先遇到a1=0。因此不妨大胆猜测,如果最小值是a1,那么先手的Alice必败,否则Alice会赢。

给出严格的数学归纳法证明:

当数列最小值x为1时:

1、如果a1 = 1,则先手必败,因为先手将其减为0之后换到其他地方,后手只需要操作完毕之后再将其换回第一位。

2、a1 > 1,则先手必胜,因为先手将a1减1之后可以直接把a1和1进行交换。就变成了情况1。

假设数列最小值为x时,结论成立,即a1 = x时先手必败,否则先手必胜。我们需要证明该结论在数列最小值为x+1时也成立。

1、若a1 = x + 1,则先手必败,因为先手将其减1之后a1 = x,再将其换到其他位置,后手只需要再将这个最小值换回去,先手拿到的就是a1 = x的情况,是必败态。

2、若a1 > x + 1,则先手必胜,因为先手将a1减1之后,再将x + 1换到a1,后手拿到的就是a1 = x + 1这种情况,这就回到了情况1。

根据数学归纳法,结论得证。

代码(CPP):

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 10;
const int INF = 0x3fffffff;
int n, a[maxn];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cout << fixed;
    cout.precision(18);

    int t;
    cin >> t;
    while(t--)
    {
        cin >> n;
        int MinIdx = 1;
        for (int i = 1; i <= n; i++)
        {
            cin >> a[i];
            if(a[i] < a[MinIdx])
                MinIdx = i;
        }
        if(MinIdx != 1)
            cout << "Alice\n";
        else
            cout << "Bob\n";
    }
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值