Problem Description Ignatius 喜欢收集蝴蝶标本和邮票,但是Eddy的爱好很特别,他对数字比较感兴趣,他曾经一度沉迷于素数,而现在他对于一些新的特殊数比较有兴趣。
Input 本题有多组测试数据,每组包含一个整数N,1<=N<=1000000000000000000(10^18).
Output 对于每组输入,请输出在在1到N之间形式如M^K的数的总数。
Sample Input 10 36 1000000000000000000
Sample Output 4 9 10010033 |
As we konw ,1~n中能整开k次方的数有个,,也就是(int)pow(n,1.0/k)个,
而要求1~n中所有能够被整开的数有几个,那就是 pow(n,1.0/2)+ pow(n,1.0/3)+······
这样看来,有很多被重复计算了,比如能开4次方、6次方、8次方的一定能开2次方
所以,我们第一次计算开k次方的时候,就要去除所有能k的倍数次方的
而这就恰是素数的性质,由于数据在long long(2^63-1)的范围,所以只需算出前63个素数就行,
但是,万一素数与素数之间重复计算了怎么办,那就需要用到容斥原理了,加上奇数个减去偶数个
只需要统计三个素数相乘的幂就行了,因为四个会超出范围
#include<bits/stdc++.h>
#define lom long long
using namespace std;
int p[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61};
int main()
{
lom n;
while(cin>>n)
{
lom ans=1,temp;
for(int i=0;;i++)
{
temp=(lom)pow(n,1.0/p[i]);
if(temp<2) break;
ans+=temp-1;
for(int j=i+1;;j++)
{
temp=(lom)pow(n,1.0/p[i]/p[j]);
if(temp<2) break;
ans-=temp-1;
for(int k=j+1;;k++)
{
temp=(lom)pow(n,1.0/p[i]/p[j]/p[k]);
if(temp<2) break;
ans+=temp-1;
}
}
}
cout<<ans<<endl;
}
return 0;
}
/*
膜膜膜 膜 膜 膜 膜 膜
膜 膜膜膜膜膜膜膜膜 膜 膜 膜
膜 膜 膜 膜 膜 膜膜膜膜 膜膜膜膜膜膜
膜膜膜 膜膜膜膜膜 膜 膜 膜 膜 膜
膜 膜 膜 膜 膜膜膜膜膜膜膜膜膜膜膜 膜 膜 膜 膜
膜 膜 膜膜膜膜膜 膜 膜膜 膜膜膜膜膜膜
膜膜膜 膜 膜 膜 膜 膜膜 膜膜 膜 膜
膜 膜 膜膜膜膜膜 膜 膜 膜 膜 膜 膜 膜
膜 膜 膜 膜 膜 膜 膜膜膜膜膜膜
膜 膜膜膜膜膜膜膜膜 膜 膜 膜 膜 膜 膜
膜 膜 膜 膜 膜 膜 膜 膜
膜 膜膜 膜 膜膜 膜膜 膜膜 膜 膜
*/