题解:
符合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;
}