HDU 2204 Eddy's 爱好(容斥原理、给定n求满足p=m^k <= n的p的个数)

博客探讨了如何解决HDU 2204问题,即计算在1到n范围内,有多少个数p满足p=m^k且m和k为正整数,k大于1。通过分析,提出了枚举幂次k的方法,限制枚举范围在60以内,从而减少计算复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:
HDU 2204 Eddy’s 爱好
题意;
给一个 n ,在p[1,n]范围满足 mk=p(m1,k>1 的数字 p 的个数。
数据范围:1n1018
分析:
一开始我一直是从枚举 m 考虑,实在不知道怎么搞,耗时太多了。。。只能借助万能的网友。。。

我们可以枚举幂次k,考虑到 260>1018 ,最多只需要枚举到 60 幂次。
同时对于一个数 p 的幂次k是个合数,那么 k 一定可以表示成k=rk,k的形式,那么:

p=mk=mrk=(mr)k

所以我们只需要枚举素幂次 k 即可。
同时如果pkn,那么对于任意的 p<p ,也一定满足 pkn 。所以对于每个 k 我们令pk=np=n1n,求出最大的 p ,同时也就是满足pkn的所有 p 的个数。
但是这样子会有重复。例如:k=2(22)3 k=3,(23)2 就重复计数了(都是 26 )。这时候需要用容斥原理:加上奇数个素幂次相乘的个数,减去偶数个素幂次相乘的个数。又因为 235<60,2357>60 ,那么最多只要考虑三个素幂次相乘情况。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const ll prime[20] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59};
const int len = 17;
const double eps = 1e-8;

ll ans;
double n;

void dfs(int cur, int num, int total, ll k)
{
    if(k > 60) return; //素因子连乘最多不能超过60次幂,因为2 ^ 60 > 10 ^ 18
    if(num == total) {
        ll p = (ll)(pow(n, 1.0 / (0.0 + k)) + eps) - 1; //先把1去掉,eps精度误差
        ans += p;
        return ; 
    }
    if(cur == len) return ;
    dfs(cur + 1, num, total, k); //第i个素数不选
    dfs(cur + 1, num + 1, total, k * prime[cur]); //第i个素数选择
}

int main()
{
    while(~scanf("%lf", &n)) {
        ll res = 0;
        for(int i = 1; i <= 3; ++i) {
            ans = 0;
            dfs(0, 0, i, 1); 
            //从下标0开始,当前选择素数个数为0,需要选择素数个数i个,选择素数乘积为1
            if(i & 1) res += ans;
            else res -= ans;
        }
        res += 1; //1在dfs时都没有统计
        printf("%lld\n", res);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值