如果一个数各个数位上的数字之和是质数,并且各个数位上的数字的平方和也是质数,则称它为幸运数。 给定x,y,求x,y之间( 包含x,y,即闭区间[x,y])有多少个幸运数。 例如1到20之间有4个幸运数,它们是11,12,14,16,像因为1+1 = 2是质数,1^2 + 1^2 = 2也是质数等等。 给定函数原型,其中1<=x<=y<=1000000000,请完成函数,实现上述功能。
以下代码可以实现,但对1-1000000000的估计有20多秒才会返回结果。
int prime_num[]={0,
0,2,3,0,5,0,7,0,0,0,11,0,13,0,0,0,17,0,19,0,
0,0,23,0,0,0,0,0,29,0,31,0,0,0,0,0,37,0,0,0,
41,0,43,0,0,0,47,0,0,0,0,0,53,0,0,0,0,0,59,0,
61,0,0,0,0,0,67,0,0,0,71,0,73,0,0,0,0,0,79,0,
0,0,83,0,0,0,0,0,89,0,0,0,0,0,0,0,97,0,0,0,
101,0,103,0,0,0,107,0,109,0,0,0,113,0,0,0,0,0,0,0,
0,0,0,0,0,0,127,0,0,0,131,0,0,0,0,0,137,0,139,0,
0,0,0,0,0,0,0,0,149,0,151,0,0,0,0,0,157,0,0,0,
0,0,163,0,0,0,167,0,0,0,0,0,173,0,0,0,0,0,179,0,
181,0,0,0,0,0,0,0,0,0,191,0,193,0,0,0,197,0,199,0,
0,0,0,0,0,0,0,0,0,0,211,0,0,0,0,0,0,0,0,0,
0,0,223,0,0,0,227,0,229,0,0,0,233,0,0,0,0,0,239,0,
241,0,0,0,0,0,0,0,0,0,251,0,0,0,0,0,257,0,0,0,
0,0,263,0,0,0,0,0,269,0,271,0,0,0,0,0,277,0,0,0,
281,0,283,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,
0,0,0,0,0,0,307,0,0,0,311,0,313,0,0,0,317,0,0,0,
0,0,0,0,0,0,0,0,0,0,331,0,0,0,0,0,337,0,0,0,
0,0,0,0,0,0,347,0,349,0,0,0,353,0,0,0,0,0,359,0,
0,0,0,0,0,0,367,0,0,0,0,0,373,0,0,0,0,0,379,0,
0,0,383,0,0,0,0,0,389,0,0,0,0,0,0,0,397,0,0,0,
401,0,0,0,0,0,0,0,409,0,0,0,0,0,0,0,0,0,419,0,
421,0,0,0,0,0,0,0,0,0,431,0,433,0,0,0,0,0,439,0,
0,0,443,0,0,0,0,0,449,0,0,0,0,0,0,0,457,0,0,0,
461,0,463,0,0,0,467,0,0,0,0,0,0,0,0,0,0,0,479,0,
0,0,0,0,0,0,487,0,0,0,491,0,0,0,0,0,0,0,499,0,
0,0,503,0,0,0,0,0,509,0,0,0,0,0,0,0,0,0,0,0,
521,0,523,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
541,0,0,0,0,0,547,0,0,0,0,0,0,0,0,0,557,0,0,0,
0,0,563,0,0,0,0,0,569,0,571,0,0,0,0,0,577,0,0,0,
0,0,0,0,0,0,587,0,0,0,0,0,593,0,0,0,0,0,599,0,
601,0,0,0,0,0,607,0,0,0,0,0,613,0,0,0,617,0,619,0,
0,0,0,0,0,0,0,0,0,0,631,0,0,0,0,0,0,0,0,0,
641,0,643,0,0,0,647,0,0,0,0,0,653,0,0,0,0,0,659,0,
661,0,0,0,0,0,0,0,0,0,0,0,673,0,0,0,677,0,0,0,
0,0,683,0,0,0,0,0,0,0,691,0,0,0,0,0,0,0,0,0,
701,0,0,0,0,0,0,0,709,0,0,0,0,0,0,0,0,0,719,0,
0,0,0,0,0,0,727,0,0
};//729以内素数,(1000000000以内最大:9个9每位平方相加得729)
const int square_num[]={0,1,4,9,16,25,36,49,64,81};
int lucky(int x,int y)
{
int iLuckyNumber = 0;
int n=0;
int i;
for (n = x; n <= y; n ++)
{
int num = n;
int numArr[10] = {0};
for (i = 0; i <10; ++i)
{
numArr[i] = num % 10;
if((num /=10)==0)break;
}
int iAddSum = numArr[0] + numArr[1] + numArr[2] + numArr[3] + numArr[4] + numArr[5] +
numArr[6] + numArr[7] + numArr[8] + numArr[9];
int isqrtSum =square_num[numArr[0]]+square_num[numArr[1]]+square_num[numArr[2]]+square_num[numArr[3]]+square_num[numArr[4]]+
+square_num[numArr[5]]+square_num[numArr[6]]+square_num[numArr[7]]+square_num[numArr[8]]+square_num[numArr[9]];
if(prime_num[iAddSum]&&prime_num[isqrtSum])
{
//printf("number =%d\n" , n);
++iLuckyNumber ;
}
}
return iLuckyNumber;
}
后找到个取巧的方法:就是把整个1-1000000000划分区间,对每个区间先求出来,对输入[x,y]按区间分割,对区间内的直接加。。不到一个区间的再调用以上方法算出来,原来区间大小取5000000,我机器上可以,最大2点多秒,但提交上去貌似超时了,只有再往下划分了,区间大小1000000应该就可以了。
int luck_num=5000000;
int luck[]={
463448,433757,458104,443231,459072,446850,448125,438665,452604,443181,449366,436941,442002,428857,445764,429509,437404,
413814,431150,407235,458104,443232,451819,447480,460081,453735,442624,433906,445129,441962,451461,447361,443647,435141,
437442,430637,453711,432720,434051,410451,459072,446851,460081,453735,460801,441563,444240,436895,460539,453361,445568,
434207,448352,432096,456597,440796,444154,413277,437731,404888,448125,438665,442624,433906,444240,436895,438344,439080,
438767,437717,441397,428076,436874,418500,439758,421916,441127,407975,427107,394485,452604,443182,445129,441962,460539,
453360,438767,437717,451245,441228,455853,440994,445990,424007,435153,409748,450747,417457,429705,398543,449366,436941,
451461,447361,445568,434207,441397,428076,455853,440994,441519,415305,439154,409389,448590,417808,436090,391486,422226,
380794,442002,428858,443647,435141,448352,432096,436874,418500,445990,424008,439154,409389,439402,399550,427837,397793,
420090,374830,412119,372708,445764,429509,437442,430637,456597,440796,439758,421915,435153,409748,448590,417807,427837,
397793,421771,391244,428814,391173,405593,374951,437404,413814,453711,432720,444154,413278,441127,407975,450747,417457,
436090,391486,420090,374830,428814,391173,406459,364263,393789,354934,431150,407235,434051,410451,437731,404888,427107,
394486,429705,398543,422226,380794,412119,372708,405593,374951,393789,354934,381876,353391
};
//luck_double用来处理区间点重复计算的问题的
int luck_double[]={
0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,
1,0,1,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0
};
int lucky_2(int x,int y);
int lucky(int x,int y)
{
int iLuckyNum=0;
int first_num=(x/luck_num);
int first_1=first_num*luck_num;
//int first_2=x%luck_num;
int last_num=(y/luck_num);
int last_1=last_num*luck_num;
//int last_2=y%luck_num;
int i=0;
for(i=first_num ; i<last_num ; ++i)
{
iLuckyNum+=luck[i]-luck_double[i];
}
iLuckyNum+=luck_double[first_num]+luck_double[last_num-1];
//printf("%d,%d,%d,%d,%d\n",first_1,last_1,iLuckyNum,lucky_2(first_1,x),lucky_2(last_1,y));
if(first_1==last_1)
return lucky_2(x,y);//luck_2就是上面的luck
if(x-first_1>luck_num/2)
iLuckyNum-=lucky_2(first_1,x);
else
{
iLuckyNum=iLuckyNum-luck[first_num]+luck_double[first_num]+lucky_2(x,first_1+luck_num-1);
}
if(y-last_1>luck_num/2)
iLuckyNum+=lucky_2(last_1+1,y);
else
{
iLuckyNum=iLuckyNum+luck[last_num]-luck_double[last_num-1]-lucky_2(y,last_1+luck_num);
}
return iLuckyNum;
}
太取巧了,个人感觉。算法无关。。。唉。。再想下有什么其他的方法没?