【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 
#include 
#include 
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;
}

你可能感兴趣的:(算法竞赛,icpc,c++,AtCoder,算法)