Eddy's爱好
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 900 Accepted Submission(s): 397
Problem Description
Ignatius 喜欢收集蝴蝶标本和邮票,但是Eddy的爱好很特别,他对数字比较感兴趣,他曾经一度沉迷于素数,而现在他对于一些新的特殊数比较有兴趣。 这些特殊数是这样的:这些数都能表示成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
Author
Eddy
Recommend
lcy
题意:给你一个正整数N,确定在1到N之间有多少个可以表示成M^K(K>1)的数。
我们可以由n^(1/p),知道指数为p的有多少个数。
通过观察,可以发现若一个数可以表示成x^(k*t),则可以表示成(x^k)^t。因此指数必然为素数。
枚举素数便可以得到指数为p的个数,但是可能出现重复,例如:x^3=y^5,其中x=t^5,y=t^3。
运用容斥原理,设a[i]表示指数为第i个素数的个数,那么答案等于满足一个的,减去两个的,加上三个的……
由于2^60>10^18,2*3*5*7>60,所以只要枚举到三即可。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int N=65; #define eps 1e-8 int prime[N],isprime[N]; void getPrime(){ int i,j; prime[0]=0; for(i=0;i<N;i++) isprime[i]=1; for(i=2;i<N;i++) if(isprime[i]){ prime[++prime[0]]=i; for(j=2;i*j<N;j++) isprime[i*j]=0; } } int main(){ //freopen("input.txt","r",stdin); long long n,tmp; getPrime(); while(cin>>n){ int ans=1; for(int i=1;i<=prime[0];i++){ tmp=(long long)(pow((double)n,1.0/prime[i])+eps); //不加eps则WA if(tmp==1) //减枝,下同 break; ans+=tmp-1; } for(int i=1;i<=prime[0];i++) for(int j=i+1;j<=prime[0];j++){ tmp=(long long)(pow((double)n,1.0/(prime[i]*prime[j]))+eps); if(tmp==1) break; ans-=(tmp-1); } for(int i=1;i<=prime[0];i++) for(int j=i+1;j<=prime[0];j++) for(int k=j+1;k<=prime[0];k++){ tmp=(long long)(pow((double)n,1.0/(prime[i]*prime[j]*prime[k]))+eps); if(tmp==1) break; ans+=(tmp-1); } printf("%d\n",ans); } return 0; }