HZNUOJ 2591 Little Sub and Johann

题解:

符合nim游戏,那么问题的关键就是求sg值了。

一头雾水的话就一步步来吧。

可以按照下面的过程一步步去网上找资料。(如果你要被我气走了,先点个赞。。。

1.了解nim游戏(强烈建议做一下这题,做完会明白很多  http://acm.hdu.edu.cn/showproblem.php?pid=1847

2.了解sg(本人看完只知其然而不知其所以然还是硬着头皮做掉了  o(╥﹏╥)o)

3.sg数组打表找规律(不管时间复杂度,先用蠢办法算出几十项找找规律)

4.找到规律

sg[i]  --->i是质数,已知i是第x个质数,则,sg[i] = x+1

         --->不是的话,sg[i] = sg[最小值因子]

5.了解线性筛求质数

6.发现线性筛就是为求这个sg准备的

线性筛的代码:

#include<cstdio>
#include<cstring>
using namespace std;
const int N =1e4+5;
bool check[N];
int prime[N];
int tot=0;
void getprime()
{
    memset(check,false,sizeof check);
    for (int i=2;i<=N;i++){
        if (!check[i]){
            prime[tot++] = i;
        }
        for (int j=0;j<tot;j++){
            if (i*prime[j] > N) break;
            check[i*prime[j]] = true;
            if (i%prime[j]==0) break;///最难理解的一行,我把不知何时网上的理解放下面22-26行,理解的了自己理解一下
        }
    }
}
///质数的快速线性筛法,不会重复筛选
///1.对于(质数*质数)的情况:不会出现重复筛的情况
///2.对于(质数*合数)的情况:就会出现重复筛,例如4*3,6*2
///由于任意个合数可以分解为质数的乘积,p=p1*p2...*pn(p1为最小的质数)
///当一个合数乘上一个比他最小的质数还要小或等于的质数时不会重复筛,所以当p%p1=0时,停止筛选
int main()
{
    getprime();
    for (int i=0;i<tot;i++){
        printf("%d ",prime[i]);
        ///5个换一行
        if ((i+1)%5==0) puts("");
    }
    return 0;
}

然后是看了大佬代码敲出来的AC答案(脸红)

#include<cstdio>
const int N = 1e6+5;
int prime[N],sg[N],tot;
bool check[N];
void getsg()
{
    tot=0;
    sg[0]=0;
    sg[1]=1;
    for (int i=2;i<=1e6;i++){
        if (!check[i]){
            prime[++tot]=i;
            sg[i]=tot+1;
        }
        for (int j=1;j<=tot&&i*prime[j]<=1e6;j++){
            check[i*prime[j]]=true;
            sg[i*prime[j]]=sg[prime[j]];
            if (i%prime[j]==0)break;
        }
    }
}
int main()
{
    getsg();
    /*
    for (int i=0;i<=1000;i++){
        printf("sg[%d] = %d ",i,sg[i]);
        if ((i+1)%5==0) puts("");
    }
    */
    int t,n,x;
    scanf("%d",&t);
    while (t--){
        scanf("%d",&n);
        int ans=0;
        while (n--){
            scanf("%d",&x);
            ans^=sg[x];
        }
        if (ans) printf("Subconscious is our king!\n");
        else printf("Long live with King Johann!\n");
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值