zoukankan      html  css  js  c++  java
  • Miller_Rabin 判素数、Pollard_Rho 分解质因子与区间筛

    Miller_Rabin 判素数


    Pollard_Rho 分解质因子


    区间筛

    1. 筛出某区间 ([L,R]) 内的所有质数/所有数的某积性函数。 (L,Rleq 10^{12},R-Lleq 10^6)

    预处理区间 ([1,10^6]) 内的质数。对 ([1,10^6]) 内任意质数 (p) ,将区间 ([L,R])(p) 的倍数,按埃氏筛的方式筛去/算出该质因子对积性函数的贡献。最后遍历区间 ([L,R]) ,找出区间质数/算出剩余质因子对积性函数的贡献。

    例题 1:洛谷 P1835 素数密度 求区间质数:预处理 ([1,10^6]) 内质数,筛去 ([L,R]) 内非质数。

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=1e6+10;
    int L,R,isnotprime[MAXN],Isnotprime[MAXN];
    inline void sieve(){
        Isnotprime[1]=1;
        for(int i=2;i<=1e6;i++)
            if(!Isnotprime[i]){
                for(int j=i+i;j<=1e6;j+=i)
                    Isnotprime[j]=1;
                
                long long num=L+(i-L%i)%i,pos;
                if(num==i) num+=i;
                for(pos=num-L+1;num<=R;num+=i,pos+=i)
                    isnotprime[pos]=1;
            }
    }
    int main(){
        cin>>L>>R;
        sieve();
        int Cnt=0;
        for(long long i=1,j=L;j<=R;i++,j++)
            if(!isnotprime[i]) Cnt++;
        cout<<Cnt;
        return 0;
    }
    

    例题 2:洛谷 P3601 签到题 求区间 (displaystyle sum_{i=l}^r[i-oldsymbolvarphi(i)]=sum(r)-sum(l-1)-sum_{i=l}^roldsymbol varphi(i),sum(n)={n(n+1)over 2})

    等价于求区间欧拉函数:预处理 ([1,10^6]) 内质数,筛去 ([L,R]) 内质因子小于 (10^6) 的质因子部分。最后的遍历,对剩余的质因子算出对欧拉函数的贡献

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN=1e6+10;
    const ll MOD=666623333;
    ll L,R,Phi[MAXN],Val[MAXN];
    bool Isnotprime[MAXN];
    inline void sieve(){
        Isnotprime[1]=1;
        for(int i=2;i<=1e6;i++) if(!Isnotprime[i]){
            for(int j=i+i;j<=1e6;j+=i) Isnotprime[j]=1;
    
            ll num=L+(i-L%i)%i,pos;
            if(num==i) num+=i;
            for(pos=num-L+1;num<=R;num+=i,pos+=i){
                Phi[pos]=Phi[pos]/i*(i-1);
                while(Val[pos]%i==0) Val[pos]/=i;
            }
        }
    
        for(ll i=1,j=L;j<=R;i++,j++)
            if(Val[i]!=1) Phi[i]=Phi[i]/Val[i]*(Val[i]-1);//剩余质因子不为 1
    }
    inline __int128 sum(__int128 n){
        return n*(n+1)/2;
    }
    int main(){
        cin>>L>>R;
        for(ll i=1,j=L;j<=R;i++,j++) Phi[i]=Val[i]=j;
        sieve();
        ll Ans=(sum(R)-sum(L-1))%MOD;
        for(ll i=1,j=L;j<=R;i++,j++) Ans=(Ans-Phi[i])%MOD;
        Ans=(Ans+MOD)%MOD;
        cout<<Ans;
        return 0;
    }
    

    1. 筛出某区间 ([L,R]) 内的所有质数/所有数的某积性函数。 (L,Rleq 10^{18},R-Lleq 10^6)

    预处理区间 ([1,10^6]) 内的质数。对 ([1,10^6]) 内任意质数 (p) ,将区间 ([L,R])(p) 的倍数,按埃氏筛的方式筛去/算出该质因子对积性函数的贡献。剩余的质因子形式有三种:(p,p^2,pq(p,qin Primewedge p,qgeq 10^6))
    最后遍历区间 ([L,R]) ,对未筛去的数,先直接开方,判定是否为 (p^2) 形式;再用 Miller_Rabin 算法判质数/用 Pollard_Rho 算法求出最小质因子,进而求出对积性函数的贡献。

    例题:洛谷 P3653 小清新数学题 求区间莫比乌斯函数:先筛出 ([1,10^6]) 内素数,再算出区间 ([L,R]) 内小质因子对莫比乌斯函数的贡献。最后遍历 ([L,R]) 区间,先直接开方,判定是否为 (p^2) 形式,是则莫比乌斯函数直接为 (0) ;再用 Miller_Rabin 算法判质数,是则莫比乌斯函数变为相反数,否则为 (pq) 形式,(oldsymbolmu(p)oldsymbolmu(q)=1) ,莫比乌斯函数值不变

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll MAXN=1e6+10;
    ll L,R,Mu[MAXN],Val[MAXN];
    bool isnotprime[MAXN];
    inline ll fpow(ll a,ll x,ll mod) { ll ans=1; for(;x;x>>=1,a=(__int128)a*a%mod) if(x&1) ans=(__int128)ans*a%mod; return ans; }
    //快速幂
    inline ll lowbit(ll val) { return val&(-val); }
    inline bool Miller_Rabin(ll val,ll p){
        if( fpow(p,val-1,val)!=1 ) return 0;
        ll lim=lowbit(val-1),num=fpow(p,(val-1)/lim,val),Sqr;
        for(ll bit=1;bit<=lim;bit<<=1){
            Sqr=(__int128)num*num%val;
            if(Sqr==1&&num!=1&&num!=val-1) return 0;
            num=Sqr;
        }
        return 1;
    }
    inline bool isprime(ll val){
        for(int i=1;i<=37;i++) if(!isnotprime[i]){
            if(val%i==0) return val==i;
            if(!Miller_Rabin(val,i)) return 0;
        }
        return 1;
    }
    inline void sieve(){
        isnotprime[1]=1;
        for(ll num=L,pos=1;num<=R;num++,pos++) Mu[pos]=1,Val[pos]=num;
        for(int i=2;i<=1e6;i++) if(!isnotprime[i]){
            for(int j=i+i;j<=1e6;j+=i) isnotprime[j]=1;
    
            ll num=L+(i-L%i)%i,pos;
            if(num==i) num+=i;
            for(pos=num-L+1;num<=R;pos+=i,num+=i){
                int Cnt=0;
                while(Val[pos]%i==0) Val[pos]/=i,Cnt++;
                if(Cnt==1) Mu[pos]=-Mu[pos];
                else Mu[pos]=0;
            }
        }
        for(ll num=L,pos=1;num<=R;num++,pos++) if(Val[pos]!=1) {
            ll tmp=sqrt(Val[pos])+0.5;
            if(tmp*tmp==Val[pos]) Mu[pos]=0;//p^2 形式
            else if( isprime(Val[pos]) ) Mu[pos]=-Mu[pos];//p 形式
            //pq 形式不变
        }
    }
    int main(){
        cin>>L>>R;
        sieve();
        ll Ans=0;
        for(ll num=L,pos=1;num<=R;num++,pos++) Ans+=Mu[pos];
        cout<<Ans;
        return 0;
    }
    

    区间筛的一般形式:

    inline bool Miller_Rabin(ll val,ll p) {...}
    inline bool isprime(ll val) {...}
    inline ll Pollar_Rho(ll val) {...}
    inline ll f(ll p,ll k) {...}//求解 p^k 积性函数
    bool isnotprime[MAXN];
    ll F[MAXN],Val[MAXN];
    inline void sieve(){
        isnotprime[1]=1;
        for(ll num=L,pos=1;num<=R;num++,pos++) F[pos]=1,Val[pos]=num;
        for(int i=2;i<=1e6;i++) if(!isnotprime[i]){
            for(int j=i+i;j<=1e6;j+=i) isnotprime[j]=1;
    
            ll num=L+(i-L%i)%i,pos;
            if(num==i) num+=i;
            for(pos=num-L+1;num<=R;pos+=i,num+=i){
                int Cnt=0;
                while(Val[pos]%i==0) Val[pos]/=i,Cnt++;
                F[pos]*=f(i,Cnt);
            }
        }
        for(ll num=L,pos=1;num<=R;num++,pos++) if(Val[pos]!=1) {
            ll tmp=sqrt(Val[pos])+0.5;
            if(tmp*tmp==Val[pos]) F[pos]*=f(tmp,2);//p^2 形式
            else if( isprime(Val[pos]) ) F[pos]*=f(Val[pos],1);//p 形式
            else{//pq 形式不变
                tmp=Pollard_Rho(Val[pos]);
                F[pos]*=f(tmp,1);
                F[pos]*=f(Val[pos]/tmp,1);
            }
        }
    }
    
  • 相关阅读:
    算法的定义
    用标准的CSS定义你的表格样式
    Mysql存储过程中临时表的建立及游标遍历
    Ubuntu10.0下编译qt版webkit
    指针函数的一个范例,在单片机上运用它能让您的程序结构更明朗清晰,层次感强
    你若不自己爬上来,我就把你打死在水中——分享三个跟管理有关的小故事
    Windows 上使用 Github 手记
    IIS应用程序池由服务器引起常见错误号的原因分析及解决方法
    如何实施好基于MOSS的企业搜索项目(上)
    如何做好项目经理
  • 原文地址:https://www.cnblogs.com/JustinRochester/p/14243999.html
Copyright © 2011-2022 走看看