LA5059 Playing With Stones

229 篇文章 0 订阅
137 篇文章 0 订阅

You and your friend are playing a game in which you and your friend
take turns removing stones from piles. Initially there are N piles
with a 1 ;a 2 ;a 3 ;:::;a N number of stones. On each turn, a player
must remove at least one stone from one pile but no more than half of
the number of stones in that pile. The player who cannot make any
moves is considered lost. For example, if there are three piles with
5, 1 and 2 stones, then the player can take 1 or 2 stones from rst
pile, no stone from second pile, and only 1 stone from third pile.
Note that the player cannot take any stones from the second pile as 1
is more than half of 1 (the size of that pile). Assume that you and
your friend play optimally and you play rst, determine whether you
have a winning move. You are said to have a winning move if after
making that move, you can eventually win no matter what your friend
does. Input The rst line of input contains an integer T ( T 100)
denoting the number of testcases. Each testcase begins with an integer
N (1 N 100) the number of piles. The next line contains N
integers a 1 ;a 2 ;a 3 ;:::;a N (1 a i 2 10 18 ) the number of
stones in each pile. Output For each testcase, print YES ' (without
quote) if you have a winning move, or
NO ’ (without quote) if you
don’t have a winning move.

O(nai2) 暴力求SG函数的做法比较显然,但是时间无法承受。可以先打表找规律。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[25];
bool vis[25];
int main()
{
    int i,j;
    f[1]=0;
    for (i=2;i<=20;i++)
    {
        memset(vis,0,sizeof(vis));
        for (j=1;2*j<=i;j++)
          vis[f[i-j]]=1;
        for (j=0;;j++)
          if (!vis[j])
          {
            f[i]=j;
            break;
          }
    }
    for (i=1;i<=20;i++)
      printf("%d:%d\n",i,f[i]);
}

可以发现,SG函数 f(x) 可以这样计算

f(x)={x/2f(x/2)(x)(x)

这样复杂度就是 O(nlogai)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
LL f(LL x)
{
    while (x&1) x/=2;
    return x/2;
}
int main()
{
    int n,T;
    LL now,x;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        now=0;
        while (n--)
        {
            scanf("%lld",&x);
            now^=f(x);
        }
        if (now) printf("YES\n");
        else printf("NO\n");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值