2018.5.23.T4 Number

Number

【题目描述】

最近Answer正在研究“幂次数”,一个正整数?被称为“幂次数”当且仅当
存在 X = y k ( y > 0 , k > 1 )
好奇的Answer想要知道在1~?中有多少数是幂次数。

【输入格式】

输入文件number.in 包含1 个正整数?

【输出格式】

输出文件number.out 包含一个非负整数表示1~N中幂次数的个数

【样例输入1】

10

【样例输出1】

4

【样例解释】

1~10 中的幂次数有1,4,8,9

【样例输入2】

36

【样例输出2】

9

【数据规模】

对于40%的数据,N ≤ 10^6
对于70%的数据,N ≤ 10^12
对于100%的数据,N ≤ 10^18


这题我只会一种暴力的做法,时间复杂度大约 O ( n 3 l o g n )
先将 n 3 内的贡献暴力求出来,如果 n 3 < <= s q r t ( n ) ,res++;
因为如果 n 3 < i <= s q r t ( n ) ,他的贡献显然为1,这一段可以直接算,在减去res即可

#include <cstdio>
#include <bitset>
#include <cmath>
using namespace std;
#define LL long long
bitset<10000007>vis;
LL n,k=1,ans=1,res;
LL find(LL s) {
    LL h=1,t=1000001;
    while (h<=t) {
        LL mid=(h+t)>>1;
        if (mid*mid*mid>s) t=mid-1;
        else h=mid+1;
    }
    if (h*h*h>s) h--;
    return h;
}
int main() {
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    scanf("%lld",&n);
    if (n<1) {
        puts("0");
        return 0;
    }
    k=find(n);
    int z=sqrt(n);
    for (LL i=2;i<=k;i++) {
        if (vis[i]) continue;
        vis[i]=1;
        LL j;
        for (j=i*i;j<=k;j*=i) vis[j]=1,ans++;
        for (;;j*=i) {
            if (j<=z) res++;
            ans++;
            if (j>n/i) break;
        }
    }
    printf("%lld\n",ans+z-k-res);
}

好吧,还有yk等dalao秒出 O ( l o g n 2 ) 做法,
我们先借用刚才的思想,找出不同根号段下的贡献,这些贡献显然是有重叠的
我们加上质因子个数为奇数的,减去为偶数的,(据说这就是莫比乌斯函数!)

#include <cstdio>
using namespace std;
#define LL long long
LL n,ans,b;
LL t[100];
LL find(int x) {
    LL h=1,t=n,p;
    while (h<t) {
        LL mid=(h+t+1)>>1;
        p=n;
        for (int i=1;i<=x;i++) p/=mid;
        if (p>=1) h=mid;
        else t=mid-1;
    }
    return h;
}
int main() {
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    scanf("%lld",&n);
    ans=1;
    for (int i=2;i<=64;i++) {
        b=1-t[i];
        for (int j=i;j<=64;j+=i) t[j]+=b;
        ans+=(find(i)-1)*b;
    }
    printf("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_41893580/article/details/80436958