[AGC002E]Candy Piles-博弈论

Candy Piles

Problem Statement

There are N piles of candies on the table. The piles are numbered 1 through N. At first, pile i contains ai candies.

Snuke and Ciel are playing a game. They take alternating turns. Snuke goes first. In each turn, the current player must perform one of the following two operations:

Choose a pile with the largest number of candies remaining, then eat all candies of that pile.
From each pile with one or more candies remaining, eat one candy.
The player who eats the last candy on the table, loses the game. Determine which player will win if both players play the game optimally.

Constraints

1≤N≤105
1≤ai≤109

Input

The input is given from Standard Input in the following format:

N
a1 a2 … aN

Output

If Snuke will win, print First. If Ciel will win, print Second.

Sample Input 1

2
1 3

Sample Output 1

First

At the beginning of the game, pile 2 contains the most candies. If Snuke eats all candies of this pile, Ciel has no choice but to eat the last candy.

Sample Input 2

3
1 2 1

Sample Output 2

First

If Snuke eats one candy from each pile, Ciel is again left with the last candy.

Sample Input 3

3
1 2 3

Sample Output 3

Second

杨氏图表???
好像在哪里见过……
然而并不是什么有用的东西……


题意:
n 堆糖果,每堆分别有a1,a2...an颗糖。
每次一个人可以选择从每一堆里吃一颗糖,或者选择最大的一堆糖吃掉。
求谁能赢。

思路:
按a排序。
然后就得到了一张这样的东西,如果喜欢的话你甚至可以叫他“杨氏图表”:

000
0000
000000000
000000000000
000000000000

然后可以发现每个人的决策可以被描述成一条折线,像这样:

000
0001
001100000
111000000000
100000000000

这里令当前所在坐标为边界,那么向右走一步代表从每一堆取一颗,向上走一步代表取走最大的一堆。
那么考虑输赢情况,首先与边界相邻的显然必败。
由于只能往上和右,所以上和右均为必输态的为必胜态。
那么打表:

111
0101
101011111
010101010111
101010101101

这里令1为必败,0为必胜。
那么可以发现,离原点最近的一个,横坐标等于纵坐标的,不紧贴边界的,坐标值最大的点与起点的状态相同。

那么 O(n) 扫一遍就可以过了~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>

using namespace std;

const int N=100009;
int n,a[N],ans;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);

    sort(a+1,a+n+1);
    reverse(a+1,a+n+1);

    for(int i=1;i<=n;i++)
        if(i+1>a[i+1])
        {
            for(int j=i+1;a[j]==i;j++)
                ans^=1;
            ans|=(a[i]-i)&1;
            puts(ans? "First":"Second");
            return 0;
        }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值