Skip to content

Meiseel Lehmer算法(版本一) ​

cpp
struct Meissel_Lehmer{
    //通过知道前面的 n^1/3 的质数可以推断后面n^2/3的质数所以可以适当减小
    static const int M=7;
    static const int PM=2*3*5*7*11*13*17;
    static const int N=5e6+5;
    vector<bool> np;//是否是素数
    vector<T> prime,pi;// 质数容器,质数个数
    vector<vector<T>> phi;
    vector<T> sz;
    int n;
    Meissel_Lehmer(){
        init();
    }
    void sieve(){
        int c=0;
        np[0]=np[1]=1;
        pi[0]=pi[1]=0;
        for(int i=2;i<N;i++){
            if(!np[i])prime[++c]=i;
            pi[i]=c;
            for(int j=1;j<=c&&prime[j]*i<N;j++){
                np[prime[j]*i]=1;
                if(i%prime[j]==0)break;
            }
        }
    }
    void init(){
        np.resize(N,0);
        pi.resize(N,0);
        prime.resize(N,0);
        phi.resize(PM+1,vector<T>(M+1,0));
        sz.resize(M+1,0);
        sieve();
        sz[0]=1;
        for(int i=0;i<=PM;i++)phi[i][0]=i;
        for(int i=1;i<=M;i++){
            sz[i]=prime[i]*sz[i-1];
            for(int j=1;j<=PM;j++)phi[j][i]=phi[j][i-1]-phi[j/prime[i]][i-1];
        }
    }
    int Sqrt(T x){
        int r=sqrtl(x-0.1);
        while(r*r<=x)r++;
        return r-1;
    }
    int Cbrt(T x){
        int r=cbrtl(x-0.1);
        while(r*r*r<=x)r++;
        return r-1;
    }
    T get_phi(T x,int s){
        if(s==0)return x;
        if(s<=M)return phi[x%sz[s]][s]+(x/sz[s])*phi[sz[s]][s];
        if(x<=prime[s]*prime[s])return pi[x]-s+1;
        if(x<=prime[s]*prime[s]*prime[s]&&x<N){
            T tmp=pi[Sqrt(x)];
            T ans=pi[x]-(tmp+s-2)*(tmp-s+1)/2;
            for(int i=s+1;i<=tmp;i++)ans+=pi[x/prime[i]];
            return ans;
        }
        return get_phi(x,s-1)-get_phi(x/prime[s],s-1);
    }
    T get_pi(int x){
        if(x<N)return pi[x];
        T ans=get_phi(x,pi[Cbrt(x)])+pi[Cbrt(x)]-1;
        for(int i=pi[Cbrt(x)]+1,ed=pi[Sqrt(x)];i<=ed;i++)ans-=get_pi(x/prime[i])-i+1;
        return ans;
    }
    T lehmer(T x){
        if(x<N)return pi[x];
        T a=lehmer(Sqrt(Sqrt(x)));
        T b=lehmer(Sqrt(x));
        T c=lehmer(Cbrt(x));
        T ans=get_phi(x,a)+(b+a-2)*(b-a+1)/2;
        for(int i=a+1;i<=b;i++){
            T w=x/prime[i];
            ans-=lehmer(w);
            if(i>c)continue;
            T lim=lehmer(Sqrt(w));
            for(int j=i;j<=lim;j++)ans-=lehmer(w/prime[j])-j+1;
        }
        return ans;
    }
};