Pollard-Rho

Solution

用于拆解较大数的质因子。

前置知识:Miller Rabin

涉及到的思想:

  • 利用 \(\gcd(x,y)\) 来寻找 \(x\) 的因数。

  • 组合随机采样的优秀命中率。

  • \(\gcd(x\cdot z,y)=\gcd(\gcd(x,y)\times \gcd(z,y),y)\),因此可以调整步长来判断当前是否找到了因数,减少 \(\gcd\) 的调用次数。

安利一篇博文,这里面讲得挺详细的,就是有些地方……可能需要你自己理解他真正的意思。


三道板子题

【模板】Pollard-Rho算法

SP4941 FACT1 - Integer Factorization (20 digits)

「数学」约数个数和

确实算是板题,毕竟这个东西就是把数字质因子拆分。

其中第三道题转化完以后就是个 前缀和 的模板。


Code

下面是封装好的,可以直接调用,返回质因数拆分的结果。

测试了 \(114514,1919810\) 这两个数的拆分。

namespace Pollard_Rho
{
    inline LL les(LL x,LL y){return x>y?x-y:y-x;}
    inline LL Gcd(LL x,LL y){return !y?x:Gcd(y,x%y);}
    inline LL prpr(LL x,LL y,LL p){LL s=(long double)x/p*y+1e-8;s=(ULL)(x*y)-(ULL)(s*p);if(s>=p)s-=p;return s<0?s+p:s;}
    inline LL ksm(LL x,LL y,LL p){LL ans=1;for(;y;y>>=1){if(y&1)ans=prpr(ans,x,p);x=prpr(x,x,p);}return ans;}

    bool pri[20];
    vector<int>prime;
    inline void init()
    {
        for(int i=2;i<20;i++){if(!pri[i])prime.push_back(i);for(auto j:prime){int now=i*j;if(now>=20)break;pri[now]=true;if(i%j==0)break;}}
        pri[1]=true;srand(time(0));return;
    }
    inline bool Miller_Rabin(LL n,int a)
    {
        LL t=n-1,lst;int k=0;for(;!(t&1);t>>=1)k++;lst=t=ksm(a,t,n);
        for(int i=1;i<=k;i++){t=prpr(t,t,n);if(t==1&&lst!=1&&lst!=n-1)return false;lst=t;}return lst==1;
    }
    inline bool ifprime(LL n){if(n<20)return !pri[n];if(n%6!=1&&n%6!=5)return false;for(auto j:prime)if(!Miller_Rabin(n,j))return false;return true;}

    inline LL f(LL x,int c,LL p){LL nows=prpr(x,x,p)+c;if(nows>=p)nows-=p;return nows;}
    inline LL Ame(LL n)
    {
        LL s,t,c;s=t=0;c=rand()%(n-1)+1;
        for(int ed=1;;ed<<=1)
        {
            LL pro=1;s=t;for(int i=1;i<=ed;i++){t=f(t,c,n),pro=prpr(pro,les(t,s),n);if(i%127==0){LL ans=Gcd(n,pro);if(ans>1)return ans;}}
            LL ans=Gcd(n,pro);if(ans>1)return ans;
        }
        return n;
    }
    vector<pair<LL,int> >getpm;
    inline void Gura(LL n,int cutt)
    {
        if(n==1)return;if(ifprime(n)){getpm.push_back(make_pair(n,cutt));return;}
        LL p=n;for(;p==n;p=Ame(n));int c=0;for(;n%p==0;n/=p)c++;Gura(n,cutt);Gura(p,cutt*c);return;
    }
    inline vector<pair<LL,int> > work(LL n)
    {
        getpm.clear();Gura(n,1);sort(getpm.begin(),getpm.end());vector<pair<LL,int> >ans;ans.clear();
        for(vector<pair<LL,int> >::iterator i=getpm.begin(),j;i!=getpm.end();i=j)
        {
            int sum=0;for(j=i;j!=getpm.end()&&j->first==i->first;j++)sum+=j->second;
            ans.push_back(make_pair(i->first,sum));
        }
        return ans;
    }
}
int main()
{
    using namespace Pollard_Rho;init();
    vector<pair<LL,int> >a=work(114514);for(vector<pair<LL,int> >::iterator i=a.begin();i!=a.end();i++)printf("%lld^%d ",i->first,i->second);puts("");
    vector<pair<LL,int> >b=work(1919810);for(vector<pair<LL,int> >::iterator i=b.begin();i!=b.end();i++)printf("%lld^%d ",i->first,i->second);puts("");
    return 0;
}
posted @ 2021-04-23 11:49  zjjws  阅读(123)  评论(0编辑  收藏  举报