Loading

Lucy-Hedgehog 算法

Lucy-Hedgehog 算法用于求解 \(\pi(n)\)\(\pi(n)\) 表示 \(1 \sim n\) 的整数中质数的个数。

Lucy-Hedgehog 算法由 Project Euler 用户 Lucy-Hedgehog 提出。(Lucy-Hedgehog 原文章)(我的转载

算法思想:

回顾埃氏筛的过程,对于每个质数 \(p\),筛掉 \(p\) 的倍数。

定义函数 \(S(v,p)\) 表示用不超过 \(p\) 的质数筛 \(1 \sim v\) 后剩余的数的个数(除去 \(1\))。

比如 \(S(10,3)\)\(1 \sim 10\) 内,通过 \(2\) 筛去 \(4,6,8,10\),通过 \(3\) 筛去 \(6,9\),除去 \(1\) 剩余 \(2,3,5,7\)。因此 \(S(10,3)=4\).

对于 \(S(v,p)\)

  • \(p\) 不是质数,\(S(v,p)=S(v,p-1)\)

  • \(p*p>v\)\(p\) 不可能再筛任何数,\(S(v,p)=S(v,p-1)\)

  • \(p\) 是质数且 \(p*p \le v\),假设 \(x=p \times k\) 能被筛掉,则 \(p \le k \le v/p\)\(k\) 不被不超过 \(p-1\) 的质数整除,这样的 \(k\) 共有 \(S(v/p,p-1)-S(p-1,p-1)\) 个。

于是我们发现一个重要的式子:

\(S(v,p)=S(v,p-1)-(S(v/p,p-1)-S(p-1,p-1))\)\(p\) 是质数且 \(p \le \sqrt{v}\)

这个第二维可以滚动数组,于是可以用 DP 实现这个算法

最后的答案 \(\pi(n)=S(n,n)\)

long long v[MAXN],s[MAXN];
long long Lucy_Hedgehog(long long x){
    int r=(int)sqrt(x)+1,m=x/r-1;
    int cnt=0;
    for(int i=1;i<=m;i++)
    {
        v[++cnt]=i;
        s[v[cnt]]=v[cnt]-1;
    }
    for(int i=r;i>=1;i--)
    {
        v[++cnt]=x/i;
        s[v[cnt]]=v[cnt]-1;
    }
    for(int i=2;i<=r;i++)
    {
        if(s[i]>s[i-1]){
            long long sp=s[i-1];
            long long lim=1ll*i*i;
            for(int j=cnt;v[j]>=lim&&j;j--)
            {
                s[v[j]]-=(s[v[j]/i]-sp);
            }
        }
    }
    return s[x];
}

又有数论分块可以把数组空间开到 \(O(\sqrt{n})\)

long long v[MAXN],s[MAXN];
long long Lucy_Hedgehog(long long x){
    int r=(int)sqrt(x)+1,m=x/r-1;
    auto id=[&](long long i){
        if(i<=m){
            return (int)i;
        }
        else{
            return lower_bound(v+1,v+1+cnt,i)-v;
        }
    };
    int cnt=0;
    for(int i=1;i<=m;i++)
    {
        v[++cnt]=i;
        s[cnt]=v[cnt]-1;
    }
    for(int i=r;i>=1;i--)
    {
        v[++cnt]=x/i;
        s[cnt]=v[cnt]-1;
    }
    for(int i=2;i<=r;i++)
    {
        if(s[i]>s[i-1]){
            long long sp=s[i-1];
            long long lim=1ll*i*i;
            for(int j=cnt;v[j]>=lim&&j;j--)
            {
                s[j]-=(s[id(v[j]/i)]-sp);
            }
        }
    }
    return s[id(x)];
}

这个算法还可以求 \(1 \sim n\) 的整数中质数的和。

只需要把式子改为 \(S(v,p)=S(v,p-1)-p \times (S(v/p,p-1)-S(p-1,p-1))\) 就行了。

long long v[MAXN];
int128 s[MAXN];
int128 Lucy_Hedgehog(long long x){
    if(x<=1){
        return 0;
    }
    int r=(int)sqrt(x)+1,m=x/r-1;
    auto id=[&](long long i){
        if(i<=m){
            return (int)i;
        }
        else{
            return lower_bound(v+1,v+1+cnt,i)-v;
        }
    };
    int cnt=0;
    for(int i=1;i<=m;i++)
    {
        v[++cnt]=i;
        s[cnt]=(int128)v[cnt]*(v[cnt]+1)/2-1;
    }
    for(int i=r;i>=1;i--)
    {
        v[++cnt]=x/i;
        s[cnt]=(int128)v[cnt]*(v[cnt]+1)/2-1;
    }
    for(int i=2;i<=r;i++)
    {
        if(s[i]>s[i-1]){
            int128 sp=s[i-1];
            long long lim=1ll*i*i;
            for(int j=cnt;v[j]>=lim&&j;j--)
            {
                s[j]-=1ll*i*(s[id(v[j]/i)]-sp);
            }
        }
    }
    return s[id(x)];
}

总体时间复杂度 \(O(x^{\frac{3}{4}})\),空间复杂度 \(O(\sqrt{x})\)

这篇文章 写了如何将时间复杂度优化至 \(O(x^{\frac{2}{3}})\)

posted @ 2025-02-09 07:07  Mathew_Miao  阅读(20)  评论(0)    收藏  举报