[学习笔记]Pollard-Rho

之前学的都是假的

%%zzt

Miller_Rabin:Miller-Rabin与二次探测

大质数分解:

找到所有质因子,再logn搞出质因子的次数

方法:不断找到一个约数d,递归d,n/d进行分解,直到n是质数

快速幂快速乘:

ll qk(ll a,ll b,ll m){
    ll d=((long double)a/m*b);
    ll r=a*b-d*m;
    return ((ull)r+m)%m;
}
ll qm(ll x,ll y,ll mod){
    ll ret=1;
    while(y){
        if(y&1) ret=qk(ret,x,mod);
        x=qk(x,x,mod);
        y>>=1;
    }
    return ret;
}

注意快速乘:((ull)r+m)%m由于r可能<0或者>m,这一步是必须的

Miller-Rabin:

const int pri[6]={2,3,5,7,11,61};
bool M_R(ll n){
    if(n==1) return false;
    if(n==2||n==3||n==5||n==7||n==11||n==13||n==61) return true;
    if(n==46856248255981ll) return false;
    if(n%2==0||n%3==0||n%5==0||n%7==0||n%11==0||n%13==0) return false;
    ll tmp=n-1,s=0;
    while(!(tmp&1)) tmp>>=1,++s;
    for(reg i=0;i<=5;++i){
        ll p=pri[i];
        ll lp=qm(p,tmp,n);
        if(lp==1||lp==n-1) continue;
        ll las;
        for(reg j=1;j<=s;++j){
            las=lp;
            lp=qk(lp,lp,n);
            if(lp==1&&(las!=1&&las!=n-1)) return false;
        }
        if(lp!=1) return false;
    }
    return true;
}

二进制gcd

ll gcd(ll a,ll b)
{
    if(!a||!b) return a|b;
    #define ctz __builtin_ctzll
    int shift=ctz(a|b);
    b>>=shift;
    while(a)
    {
        a>>=ctz(a);
        if(a<b)
            swap(a,b);
        a-=b;
    }
    return b<<shift;
    #undef ctz
}

就是高精gcd才用的更相减损术

Pollard-Rho

主体1

ll P_R(ll n,ll c){
    ll x=0,y=0,d;
    int k=2,has=1;
    ll tmp=1;
    while(1){
        ++has;
        x=(qk(x,x,n)+c)%n;
        tmp=qk(tmp,abs(y-x),n);
        if(x==y) return n;
        if(has==k){
            y=x;k<<=1;
            d=gcd(tmp,n);
            tmp=1;
            if(d==n) break;
            if(d>1){
                return d;
            }
        }
    }
    d=1;
    while(d==1){
        x=(qk(x,x,n)+c)%n;d=gcd(abs(y-x),n);
    }
    return d;
}

注意tmp,把所有的abs(y-x)乘在一起,gcd显然不变,并且减少了求gcd次数

最后如果d=n,特殊把环再跑一边

主体2

void find(ll n,ll cnt){
    if(n==1||n<=ans) return;
    if(M_R(n)){
        ans=max(ans,n);return;
    }
    ll p=P_R(n,cnt);
    while(n==p) p=P_R(n,--cnt);
    while(n%p==0) n/=p;
    find(p,cnt);find(n,cnt);
}

如果要求质因子,开个vector,最后去重即可

模板:

【模板】Pollard-Rho算法 

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define ull unsigned long long
#define LL ll
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}

namespace Miracle{
int t;
ll n,ans;
ll qk(ll a,ll b,ll m){
    ll d=((long double)a/m*b);
    ll r=a*b-d*m;
    return ((ull)r+m)%m;
}
ll qm(ll x,ll y,ll mod){
    ll ret=1;
    while(y){
        if(y&1) ret=qk(ret,x,mod);
        x=qk(x,x,mod);
        y>>=1;
    }
    return ret;
}
const int pri[6]={2,3,5,7,11,61};
bool M_R(ll n){
    if(n==1) return false;
    if(n==2||n==3||n==5||n==7||n==11||n==13||n==61) return true;
    if(n==46856248255981ll) return false;
    if(n%2==0||n%3==0||n%5==0||n%7==0||n%11==0||n%13==0) return false;
    ll tmp=n-1,s=0;
    while(!(tmp&1)) tmp>>=1,++s;
    for(reg i=0;i<=5;++i){
        ll p=pri[i];
        ll lp=qm(p,tmp,n);
        if(lp==1||lp==n-1) continue;
        ll las;
        for(reg j=1;j<=s;++j){
            las=lp;
            lp=qk(lp,lp,n);
            if(lp==1&&(las!=1&&las!=n-1)) return false;
        }
        if(lp!=1) return false;
    }
    return true;
}
ll gcd(ll a,ll b)
{
    if(!a||!b) return a|b;
    #define ctz __builtin_ctzll
    int shift=ctz(a|b);
    b>>=shift;
    while(a)
    {
        a>>=ctz(a);
        if(a<b)
            swap(a,b);
        a-=b;
    }
    return b<<shift;
    #undef ctz
}
ll P_R(ll n,ll c){
    ll x=0,y=0,d;
    int k=2,has=1;
    ll tmp=1;
    while(1){
        ++has;
        x=(qk(x,x,n)+c)%n;
        tmp=qk(tmp,abs(y-x),n);
        if(x==y) return n;
        if(has==k){
            y=x;k<<=1;
            d=gcd(tmp,n);
            tmp=1;
            if(d==n) break;
            if(d>1){
                return d;
            }
        }
    }
    d=1;
    while(d==1){
        x=(qk(x,x,n)+c)%n;d=gcd(abs(y-x),n);
    }
    return d;
}
void find(ll n,ll cnt){
    if(n==1||n<=ans) return;
    if(M_R(n)){
        ans=max(ans,n);return;
    }
    ll p=P_R(n,cnt);
    while(n==p) p=P_R(n,--cnt);
    while(n%p==0) n/=p;
    find(p,cnt);find(n,cnt);
}
int main(){
    int t;
    srand(19260817);
    rd(t);
    while(t--){
        ll n;rd(n);
        ans=0;find(n,19260817);
        if(ans==n) puts("Prime");
        else printf("%lld\n",ans);
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/4/2 21:40:31
*/
View Code

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/10858196.html