51nod 1661: 黑板上的游戏(sg函数 找规律)

题目链接

先打一个sg函数的表,找找规律,发现sg函数可以递归求解

打表代码如下

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

const int N=1e5+7;

bool vis[N];
int sg[N];
int k;

void init()
{
    memset(sg,0,sizeof(sg));
    memset(vis,false,sizeof(vis));
    sg[0]=0,sg[1]=0;
    for(int i=2;i<=80;i++)
    {
        memset(vis,0,sizeof(vis));
        for(int j=(i+k-1)/k;j<i;j++)
            vis[sg[j]]=true;
        for(int j=0;j<=80;j++)
            if(vis[j]==false)
            {
                sg[i]=j;
                break;
            }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    while(cin>>k)
    {
        init();
        for(int i=1;i<=80;i++)
        {
            printf("sg[%3d]=%3d%c",i,sg[i],i%k==0? '\n':' ');
        }
        puts("");
        puts("");
    }
}
View Code

得到的一个结果

k=4
sg[  1]=  0 sg[  2]=  1 sg[  3]=  2 sg[  4]=  3
sg[  5]=  0 sg[  6]=  4 sg[  7]=  5 sg[  8]=  6
sg[  9]=  1 sg[ 10]=  7 sg[ 11]=  8 sg[ 12]=  9
sg[ 13]=  2 sg[ 14]= 10 sg[ 15]= 11 sg[ 16]= 12
sg[ 17]=  3 sg[ 18]= 13 sg[ 19]= 14 sg[ 20]= 15
sg[ 21]=  0 sg[ 22]= 16 sg[ 23]= 17 sg[ 24]= 18
sg[ 25]=  4 sg[ 26]= 19 sg[ 27]= 20 sg[ 28]= 21
sg[ 29]=  5 sg[ 30]= 22 sg[ 31]= 23 sg[ 32]= 24
sg[ 33]=  6 sg[ 34]= 25 sg[ 35]= 26 sg[ 36]= 27
sg[ 37]=  1 sg[ 38]= 28 sg[ 39]= 29 sg[ 40]= 30
sg[ 41]=  7 sg[ 42]= 31 sg[ 43]= 32 sg[ 44]= 33
sg[ 45]=  8 sg[ 46]= 34 sg[ 47]= 35 sg[ 48]= 36
sg[ 49]=  9 sg[ 50]= 37 sg[ 51]= 38 sg[ 52]= 39
sg[ 53]=  2 sg[ 54]= 40 sg[ 55]= 41 sg[ 56]= 42
sg[ 57]= 10 sg[ 58]= 43 sg[ 59]= 44 sg[ 60]= 45
sg[ 61]= 11 sg[ 62]= 46 sg[ 63]= 47 sg[ 64]= 48
sg[ 65]= 12 sg[ 66]= 49 sg[ 67]= 50 sg[ 68]= 51
sg[ 69]=  3 sg[ 70]= 52 sg[ 71]= 53 sg[ 72]= 54
sg[ 73]= 13 sg[ 74]= 55 sg[ 75]= 56 sg[ 76]= 57
sg[ 77]= 14 sg[ 78]= 58 sg[ 79]= 59 sg[ 80]= 60
View Code

当然k可以改来改去地试

再之后,如果异或和不为0,要特殊处理下,也是根据打表的规律,具体方法见代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

const int N=1e5+7;
LL k;
int n;
LL a[N];

LL sg(LL x)
{
    if(x==1||x==0) return 0;
    if(x%k!=1)
        return x-(x+k-1)/k;
    return sg(x/k);
}

int main()
{
    while(~scanf("%d%lld",&n,&k))
    {
        LL ans=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            ans^=sg(a[i]);
        }
//        cout<<ans<<endl;
        if(ans)
        {
            int pos;
            LL y;
            for(int i=1;i<=n;i++)
            {
                LL sgx=sg(a[i]),t=sgx^ans;
                pos=i;
                y=t+(t+k-2)/(k-1);
//                cout<<y<<' '<<(a[i]+k-1)/k<<endl;
                while(1)
                {
                    if(y>=a[i]) break;
                    if(y<a[i]&&y>=(a[i]+k-1)/k)
                    {
                        printf("Alice %d %lld\n",pos,y);
                        return 0;
                    }
                    y=y*k+1;
                }
            }
            printf("Alice %d %lld\n",pos,y);
        }
        else
            puts("Bob");
    }
}

 

转载于:https://www.cnblogs.com/Just--Do--It/p/7202644.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值