题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2608
题目大意是定义一个T(n)为n所有正因子之和。然后定义S(n)为T(1)+T(2)……T(n)之和,求S(n)对2取余。
显然这是一个数论题,数据范围是32位整数,范围很多大,可以猜测,应该存在某种规律。
一定要敢于尝试,而且不要手懒,我们可以很快的暴力打一个100范围的T(n)表,然后看看,能不能找出规律。这里一定不要着急,有时候直接打S(n)的表可能看不出结果,所以一定要慢慢来。
暴力打表代码如下:
#include <stdio.h>
#define M 100
int a[M];
int main()
{
int i,j;
for(i=1;i<M;i++)
{
for(j=i;j<M;j+=i)
{
a[j]+=i;
}
}
for(i=0;i<M;i++)
{
printf("%3d: %3d\n",i,a[i]&1);
}
return 0;
}
看到结果,我们发现大部分数据都是0,只有少部分是1,分别是1、2、4、8、9、16、18、25、32、36……细心点会发现T[i*i]会是,T[2*i*i]也是1,当你看出这一点时,这题可做了。题目给出N,只需求出[1,N]有多少个这样的数记为Cnt,然后把Cnt%2就可以了。像这样:
for(Cnt=0,i=1;i<N;i++)
{
if(i*i<=N)
{
Cnt++;
}
if(2*i*i<=N)
{
Cnt++;
}
}
printf("%d\n",Cnt&1);
这需要考虑如果2*i*i能写成a*a,这样就多计数了一次,但是显然可以证明,不存在那样的数。如果在舍得动一下脑筋就可以写成:
#include <stdio.h>
#include <math.h>
int main()
{
int T,s,N,k;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
k=sqrt(N);
s=k;
while(k*k*2>N)
{
k--;
}
s+=k;
printf("%d\n",s&1);
}
return 0;
}
如果再肯多想一点,sqrt(N/2.0)就是2*i*i的上限所以就可以这样写:
#include <stdio.h>
#include <math.h>
int main()
{
int T,N;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
printf("%d\n",((int)sqrt(N)+(int)sqrt(N/2.0))&1);
}
return 0;
}
其实sqrt(N/2)也是对的。显然偶数肯定对,其实奇数时也对的,因为可以证明sqrt(a)与sqrt(a+0.5)在取整之后一定一样,sqrt(a)可能为整数,但sqrt(a+0.5)是不可能为整数的,所以里面加上0.5也是不能使整数部分加一的。但是懒得想这么多,保险起见,还是尽量别丢精度。