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
意解:容斥原理,枚举指数k(k > 1),对于每一个指数,可以知道M^K<=N的最大M,然后因为当k为合数时,总是可以把其化为素数,所以只需枚举素数k,但是枚举过程会有重复,比如当x^2 = y ^ 3时,存在有数t(t>1)使得(t ^3) ^ 2 = (t ^2)^3 = t^6; 来到这里容易想到容斥原理,奇数加,偶数减;接下来就是对每一个k求解最大数M的过程了,如果直接通过枚举的话数据太大,会超时,所以可以把式子化为M<=N^(1/K),而这个可以直接利用cmath库函数中的pow函数求解M,不过因为pow参数是浮点型,所以需要注意精度问题,加上eps = 1e-8就行了.最后因为1也符合,所以结果加上一;
AC代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
vector<int>tmp;
bool is_prime(int x)
{
for(int i = 2; i <= x / i; i++)
if(x % i == 0) return false;
return true;
}
int main()
{
ll N;
while(cin>>N)
{
ll ans = 0;
tmp.clear();
for(int i = 2; i <= 100; i++)
{
if(!is_prime(i)) continue;
if((1LL << i) > N) break;
tmp.push_back(i);
}
int len = tmp.size();
for(int i = 1; i < (1LL << len); i++)
{
ll mul = 1,tp = 0;
for(int j = 0; j < len; j++)
{
if((i >> j) & 1)
{
mul *= tmp[j];
tp++;
}
}
ll isGO = (ll)(pow((double)N,1.0 / mul) + eps) - 1;
if(tp & 1) ans += isGO;
else ans -= isGO;
}
cout<<ans + 1<<endl;
}
return 0;
}