【AtCoder】137C Distinct Numbers题解

题目大意

给定一个 n n n个数的集合,Alice和Bob轮流操作,Alice先操作,每次选最大的数,将其减少任意值,再放回集合(需一直满足集合中元素互不相同的规定),集合中的数 a i ≥ 0 a_i \ge 0 ai0。谁先不能操作,谁就会输掉游戏输掉。

给定 n , a i n, a_i n,ai,问谁会获胜。

原题链接

思路

这是一道相当妙的博弈论,这个游戏是个 I C G ICG ICG,也就是说,存在必胜策略。我们把数都从小到大排序(每次执行操作后也排序)。

我们假设:

  • 先手把 a n a_n an减少到比 a n − 1 a_{n-1} an1小,是必胜策略,那么我们就直接这么做
  • 如果先手把 a n a_n an减少到比 a n − 1 a_{n-1} an1小不是必胜策略(也就是必败策略),且假设 a n > a n − 1 + 1 a_n > a_{n-1} + 1 an>an1+1,那我们先手让 a n = a n − 1 + 1 a_n = a_{n-1} + 1 an=an1+1,那么后手就只能把 a n a_n an减少到小于 a n − 1 a_{n-1} an1,然而这是个必败策略,也就是说,可以把必败情况给后手,即也是先手必胜。

那么假如 a n = a n − 1 + 1 a_n = a_{n-1} + 1 an=an1+1,那么双方的策略就一直是维持 a n = a n − 1 a_n = a_{n-1} an=an1,直到无法操作,因为一旦不满足这个条件,那么另外一方就能利用 a n > a n − 1 + 1 a_n > a_{n-1} + 1 an>an1+1这个条件取胜。

那么一直这么做的话,执行最后一步的人会取胜,而执行到最后集合一定是 0 , 1 , 2 , . . . , n − 1 0,1,2,...,n-1 0,1,2,...,n1。且我们发现操作次数其实就是 a n − ( n − 1 ) a_n - (n-1) an(n1),是的,很神奇和其它数无关,因为我们每次减少数,不能和其它数重合,且满足 a n = a n − 1 a_n = a_{n-1} an=an1,也就是说 [ 0 , a n ] [0,a_n] [0,an]中每个数都会被遍历到,所以其它数在哪都没关系。

那么可执行次数为奇数,先手必胜,否则后手必胜。

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxN = 3e5 + 7;

int n, a[maxN];

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    sort(a + 1, a + 1 + n);
    if(a[n] - a[n - 1] > 1)
        printf("Alice\n");
    else {
        if((a[n] - (n - 1)) % 2)
            printf("Alice\n");
        else
            printf("Bob\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值