Eddy's爱好
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Problem Description
Ignatius 喜欢收集蝴蝶标本和邮票,但是Eddy的爱好很特别,他对数字比较感兴趣,他曾经一度沉迷于素数,而现在他对于一些新的特殊数比较有兴趣。
这些特殊数是这样的:这些数都能表示成M^K,M和K是正整数且K>1。
正当他再度沉迷的时候,他发现不知道什么时候才能知道这样的数字的数量,因此他又求助于你这位聪明的程序员,请你帮他用程序解决这个问题。
为了简化,问题是这样的:给你一个正整数N,确定在1到N之间有多少个可以表示成M^K(K>1)的数。
这些特殊数是这样的:这些数都能表示成M^K,M和K是正整数且K>1。
正当他再度沉迷的时候,他发现不知道什么时候才能知道这样的数字的数量,因此他又求助于你这位聪明的程序员,请你帮他用程序解决这个问题。
为了简化,问题是这样的:给你一个正整数N,确定在1到N之间有多少个可以表示成M^K(K>1)的数。
Input
本题有多组测试数据,每组包含一个整数N,1<=N<=1000000000000000000(10^18).
Output
对于每组输入,请输出在在1到N之间形式如M^K的数的总数。
每组输出占一行。
每组输出占一行。
Sample Input
10 36 1000000000000000000
Sample Output
4 9 1001003332 我的思路是这样的:
把n作为double型数,对其开k次方(我们不难发现, k<61, 对于题目要求的n的最大值开61次方就小于2了)得m,则不大 m的正整数的k次方就都是要求的整数。如果我们把k从2到60循环并把(int)m都加起来,这个和是不是就是要求的答案呢? 很明显不是,如2的4次方和4的平方都是16、2的6次方和4的平方都等于64,这样以来这个和就可能大于要求的答案了。所 以k不能这样循环。我们这样:既然2的4次方和4的平方都是16、2的6次方和4的平方都等于64,那么我们何不只计4的2次方 和4的3次方不计2的4次方和2的6次方呢!即我们只需计一个数的素数次方,这样我们只用把60以内素数计下来进行计算就会 去掉了不少的重复。
是不是这样算出的结果t就是答案呢?还不是。这一点就不太好想了,让我费好长时间也找不出反例,还是同学提示才算 找到了。比如64(2的2*3次方)既是4的3次方又是8的平方。这一类属于m的k*p次方型(其中k和p为素数),这样 以来t的值还比答案大,我们就得去掉这一部分。我们将60以内的素数两两相乘取60以内的积的集合,再对n开方并去掉这部 分的重复,这样得到t的就去掉了m的k*p次方型的数重复计算。
看起来没有什么问题了,可是用上面的测试实例一测还是不对。这又是哪里出错了。经过以上种种出错,这次就不难想 出原因了。对于m的k*p*g型的数(k、p、g都是素数),它既是(m^k)^(p*g),又是(m^p)^(k*g),同时又是(m^g)^(k*p) ,这样我们的上一部操作又多去掉了一些值。这里我们把其加上就是了。对于这一类型的数在10^18之内只可能有三个: 2的2*3*5次方、2的2*3*7次方以及3的2*3*5次方。如果n包括这几个数,再加上包括的个数算出的t就是最终答案了。
以下是代码及其简要解析://以下的k、p、g都指的素数 #include<stdio.h> #include<math.h> int main() { int i,t,m; //数组a存60以内的素数,数组b存60以内的k*p型数据 double n,a[20]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59}; double k,b[18]={6,10,14,15,21,22,26,33,34,35,38,39,46,51,55,57,58}; while(scanf("%lf",&n)!=-1){ t=0; //计算m^k型数的个数 for(i=0;i<17;i++){ m=(int)pow(n,1/a[i]); //由于大数开方会有数据的损失,这里的while循环是处理数据损失的 while(pow(m+1,a[i])<=n)m++; if(m<2)break; t+=m-1; } //以上没有计算1,这里要把1 算上 t++; //去掉m^(k*p)型数的个数 for(i=0;i<17;i++){ m=(int)pow(n,1/b[i]); while(pow(m+1,b[i])<=n)m++; if(m<2)break; t-=m-1; } //补充m^(k*p*g)型数(10^18内就这三个)数据的个数 if(n>=pow(2,30))t++; if(n>=pow(2,42))t++; if(n>=pow(3,30))t++; printf("%d\n",t); } return 0; }