版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37943488/article/details/82503369
链接:https://www.nowcoder.com/acm/contest/161/B
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
小N和小O在玩游戏。他们面前放了n堆石子,第i堆石子一开始有ci颗石头。他们轮流从某堆石子中取石子,不能不取。最后无法操作的人就输了这个游戏。但他们觉得这样玩太无聊了,更新了一下规则。具体是这样的:对于一堆有恰好m颗石子的石头堆,假如一个人要从这堆石子中取石子,设他要取石子数为d,那么d必须是m的约数。最后还是无法操作者输。
现在小N先手。他想知道他第一步有多少种不同的必胜策略。一个策略指的是,从哪堆石子中,取走多少颗石子。只要取的那一堆不同,或取的数目不同,都算不同的策略。
输入描述:
第一行一个整数n。 接下来一行n个整数,分别代表每堆石子的石子数目。 数据保证输入的所有数字都不超过105,均大于等于1,且为整数。
输出描述:
一行一个整数代表小N第一步必胜策略的数量。
示例1
输入
10 47 18 9 36 10 1 13 19 29 1
输出
7
当时有点思路但是不完整也不会写...
先预处理1-100000的SG函数,对于一个数的约数,那就是对i-j和i-i/j打上标记。处理完以后,对输入的数都异或上它们的SG函数,然后对每一个数进行遍历,处理之前先异或上它的SG函数,表示我们只对当前这一堆进行操作,其他的不变,那对于当前这一堆,就看拿了它的约数以后的SG函数与其它的堆异或是否为0,然后这样统计就行了
感觉对SG函数又理解了一些
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e5+7;
int SG[maxn];
bool vis[maxn];
int num[maxn];
void getSG()
{
for(int i=1;i<=100000;i++)
{
memset(vis,false,sizeof(vis));
for(int j=1;j*j<=i;j++)
{
if(i%j==0)
{
vis[SG[i-j]]=true;
vis[SG[i-i/j]]=true;
}
}
for(int j=0;j<100001;j++)
{
if(!vis[j])
{
SG[i]=j;
break;
}
}
}
return;
}
int main()
{
getSG();
int n;
scanf("%d",&n);
int sum=0;
int res=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
sum^=SG[num[i]];
}
for(int i=1;i<=n;i++)
{
sum^=SG[num[i]];
for(int j=1;j*j<=num[i];j++)
{
if(num[i]%j==0)
{
if((SG[num[i]-j]^sum)==0) res++;
if(j*j!=num[i]&&(SG[num[i]-num[i]/j]^sum)==0)
{
res++;
}
}
}
sum^=SG[num[i]];
}
cout<<res<<endl;
return 0;
}
扫描二维码关注公众号,回复:
3206241 查看本文章