C - Eddy's爱好

C - Eddy's爱好
Time Limit:1000MS    Memory Limit:32768KB    64bit IO Format:%I64d & %I64u

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
 
意解:容斥原理,枚举指数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;
}


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值