• Pollard-Rho算法求大数质因子


    /*
     * 大整数分解到现在都是世界级的难题,但却是一个重要的研究方向,大整数在公共密钥的研究上有着重要的作用
     * Pollard Rho算法的原理就是通过某种方法得到两个整数a和b.而待分解的大整数为n,计算p=gcd(abs(a-b),n),直到p不为1或者a,b出现循环为止.
     * 然后再判断是否为n,如果p==n||p==1,那么返回n时一个质数
     * 否则p就是n的一个因子
     * 那么我们又可以递归地计算Pollard(p)和Pollard(n/p).
     * 最后就可以推出n的所有质因子
     *
     * 具体操作中我们常常使用函数 x[i+1]=(x[i]*x[i]+c)%n 来逐步迭代计算a和b的值,通常c取1,即b=a*a+1,在下一次计算中,将b的值赋给a,再次使用上式来计算新的b的值,当a,b出现循环时即可退出判断.(初值自己确定)
     * 但是这样的话判断循环比较麻烦,这里给出Floyd(没错又是他)发明的一个聪明而又有趣的算法:
     *     假设我们在一个很长很长的圆形轨道上面行走,如何知道自己已经走了一圈了呢?
     *     可以让两个人A和B按照 vb = va<<1 从同一起点开始向前走,当B第一次赶上A时,我们就知道B已经走了两圈
     *     所以我们可以把x当作B,把y当作A,然后进行循环测试
     * 
     * 对于Pollard Rho算法,它可以在O(sqrt(p))的时间复杂度内找到n的一个小因子p,可见效率还是可以的
     * 但是对于一个因子很少或者因子值很大的大整数n来说,这个算法的复杂度依然不是很好
     */
    //以下给出Pollard Rho和Miller-Rabin素数测试配合使用的整数分解算法
    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    typedef long long ll;
    const int counts = 10,N = 5001;
    
    ll tot,cnt,fac[N],num[N];
    
    ll gcd(ll a,ll b)
    {return b?gcd(b,a%b):a;}
    
    ll qpow(ll a,ll x,ll p)
    {
        ll ret=1;
        for(;x;x>>=1,a=a*a%p)
            if(x&1)
                ret=ret*a%p;
        return ret;
    }
    
    ll multi(ll a,ll b,ll p)
    {
        ll ans=0;
        a%=p;
        for(;b;b>>=1,a=(a<<1)%p)
            if(b&1)
                ans=(ans+a)%p;
        return ans;
    }
    
    bool Miller_Rabin(ll n)
    {
        if(n==2)return true;
        if(n<2 || !(n&1))return false;
        ll m=n-1,a,x,y;int k=0;
        while(!(m&1))++k,m>>=1;
        for(int i=0;i<counts;++i)
        {
            a=rand()%(n-1)+1;
            x=qpow(a,m,n);
            y=0;
            for(int j=0;j<k;++j)
            {
                y=multi(x,x,n);
                if(y==1 && x!=-1 && x!=n-1)return false;
                x=y;
            }
            if(y != -1)return false;
        }
        return true;
    }
    
    ll Pollard_Rho(ll n,ll c)
    {
        ll i=1,k=2,x=rand()%(n-1)+1,y=x,d;
        while("fighting")
        {
            ++i;
            x=(multi(x,x,n)+c)%n;
            d=gcd((y-x+n),n);
            if(1<d && d<n)return d;
            if(y == x)return n;
            if(i == k)y=x,k<<=1;
        }
    }
    
    void find(ll n,int c)
    {
        if(n == 1)return ;
        if(Miller_Rabin(n))
        {
            fac[tot++]=n;
            return ;
        }
        ll p=n,k=c;
        while(p>=n)p=Pollard_Rho(p,c--);
        find(p,k);
        find(n/p,k);
    }
    
    int main()
    {
        ll n;
        while(std::cin>>n)
        {
            tot=0;
            find(n,120);
            std::sort(fac,fac+tot);
            num[0]=1;
            int k=1;
            for(int i=1;i<tot;++i)
            {
                if(fac[i] == fac[i-1])
                    ++num[k-1];
                else
                {
                    num[k]=1;
                    fac[k++]=fac[i];
                }
            }
            cnt=k;
            for(int i=0;i<cnt;++i)
                std::cout<<fac[i]<<"^"<<num[i]<<" ";
            std::cout<<std::endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    split函数的修改,通过存储过程实现整表所有列的拆分
    在本机上安装zabbix,来监控服务器 三
    我第一篇博客
    渗透测试常用工具-网络嗅探
    渗透测试常用工具-Metasploit
    渗透测试常用工具-ADMsnmp进行snmp分析
    渗透测试常用工具-amap服务枚举
    渗透测试常用工具-端口扫描
    渗透测试常用工具-目标识别
    Meterpreter(后渗透命令)笔记
  • 原文地址:https://www.cnblogs.com/kuaileyongheng/p/9143139.html
Copyright © 2020-2023  润新知