小花梨的取石子游戏

链接:传送门

单点时限: 1.0 sec

内存限制: 512 MB

Description


小花梨有n堆石子,第i堆石子数量为ai,n堆石子顺时针编号为1−n(如图)。
游戏将进行n轮,每轮游戏单独进行,互不干扰,每轮初始时第i堆石子数目为ai。第i轮从编号为i的那堆石子为起点,顺时针来取石子。两人轮流取石子,不可不取,最少取一个石子,最多把当前这一堆取完,只有取完一堆后才走到下一堆石子。走完一圈后石子都被取完,不能取石子的人就失败。假设两人以最优策略进行取石子操作,请分别输出n轮游戏是先手胜还是后手胜。
Input
第一行为正整数n,表示石子的堆数(1≤n≤100000)第二行输入n个正整数表示每一堆的石子数目ai(1≤ai≤109)
Output
输出n行,第i行表示第i轮游戏的结果。如果先手胜则输出"First",后手胜输出"Second"。
Example
Sample InputSample Output
3
2 1 3
First
Second
First
2
2 2
First
First
Note
样例1:
游戏进行3轮第1轮游戏石子堆下标的顺序为123,此时石子数目按顺序为213,先手胜
第2轮游戏石子堆下标的顺序为231,此时石子数目按顺序为132,后手胜
第3轮游戏石子堆下标的顺序为312,此时石子数目按顺序为321,先手胜
 

思路

  我们先假设第一个数字为3,后一个数字为1,根据题意第一个人第一次需要拿2个,才能取得胜利,而如果数字排序是311的话,第一个人第一次则需要拿3个,才能取得胜利。不过由此可以看出,第一个人可以通过一个不为1的数来调节谁最后不能够拿到石子,即谁最后取得胜利。因此我们需要记录刚开始时连续的1有几个(像111221 满足该条件有3个1    112211 满足条件有2个1     222211没有满足条件的1),来确定遇到第一个不是1的数字时谁是先手状态,也就是最后谁能获胜了。该题的数据范围是n<=1e5  如果直接暴力里写的话时间复杂度是(n^2),会超出1秒的时间限制,即TL。所以需要开一个数组记录一下当前位置时连续的1有几个。

具体实现方法如下:

  for(int i=0; i<n; i++)
    {
        if(a[i]==1)
        {
            if(i==0||a[i-1]!=1)
            {
                int tep=1;
                for(int j=i+1; j<n; j++)
                {
                    if(a[j]!=1)
                        break;
                    else
                        tep++;
                }
                dis[i]=tep;
            }
            else
               dis[i]=dis[i-1]-1;
        }
        else
            dis[i]=0;
    }

而对于开头出的石子,因为下一次循环时会变成末尾的的石子,因此需要对初始序列末尾的石子加一个特判,特判如下(比如说11233111,如果按上面的那个方法当轮到后3位开始时满足条件的1分别为3,2,1,可实际上却是5,4,3因此需要特别处理一下)

 

  for(int i=n-1;i>=1;i--)
    {
        if(dis[i]!=0)
        {
            dis[i]=min(dis[0]+dis[i],n);
        }
        else
            break;
    }

而最后判断谁胜利只需要判断谁第一个非1数字开始谁是先手就可以了,而如果没有大于1的数字判断,就只需要判断一个个数了。实现代码如下:

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<string>
#include<iostream>
#define N 100001
using namespace std;
int  dis[N], mark, a[N];
int n;
int main()
{
    scanf("%d", &n);
    int flag=0;
    for (int i = 0; i < n; i++)
    {
         scanf("%d", &a[i]);
         if(a[i]!=1)
            flag=1;
    }
    for(int i=0; i<n; i++)
    {
        if(a[i]==1)
        {
            if(i==0||a[i-1]!=1)
            {
                int tep=1;
                for(int j=i+1; j<n; j++)
                {
                    if(a[j]!=1)
                        break;
                    else
                        tep++;
                }
                dis[i]=tep;
            }
            else
               dis[i]=dis[i-1]-1;
        }
        else
            dis[i]=0;
    }
    for(int i=n-1;i>=1;i--)
    {
        if(dis[i]!=0)
        {
            dis[i]=min(dis[0]+dis[i],n);
        }
        else
            break;
    }

//    for(int i=0;i<n;i++)
//        printf("%d ",dis[i]);
//    printf("\n");

    for(int i=0;i<n;i++)
    {
        if(flag)
        {
            if(dis[i]%2==0)
                printf("First\n");
            else
                printf("Second\n");
        }
        else
        {
            if(dis[i]%2==0)
                printf("Second\n");
            else
                printf("First\n");
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值