• Pollard-rho算法[因子分解算法]


    试除法:最简单的因数分解算法,从$ 2 $到$ sqrt n $一个一个试。

    试除法(改进):从$ 2 $到$ sqrt n $挑素数一个一个试。

    然而这样复杂度是相当高的。

    生日悖论:指如果一个房间里有23个或23个以上的人,那么至少有两个人的生日相同的概率要大于50%。

    我们在$ [2,n) $取一个数,该数是$ n $的因子的概率很小.

    我们取$ k $ 个数$ x_1,x_2,x_3...x_k $,而取出的 $ k $ 个数中,$ exists i,j : (x_i-x_j) | n $ 的概率随着$ k $ 增大而增高。

    我们有一个更好的办法:

    对选取的$ k $ 个数 $ x_1,x_2,x_3...x_k $,不再询问是否存在$ (x_i-x_j) | n $,改为询问 $ gcd(x_i-x_j,n)>1 $ 的情况。

    所以,一个简单的策略如下:

    1.在区间$[2,n)$ 中随即选取$ k $个数$ x_1,x_2,x_3...x_k $

    2.判断是否存在$ gcd(x_i-x_j,n)>1 $ , 若存在,$ gcd(x_i-x_j,n)>1 $ 是$ n $的一个因子。

    我们大概需要选取$ n^{frac{1}{4}}$个数,这可能存不下。

    Pollard's Rho 算法 

    为了解决数太多无法储存的问题,Pollard's Rho 算法之将两个数存在内存里,我们生成并检查这两个数,反复执行这个步骤并希望得到我们想要的数。

    我们不断使用一个函数来生成这个序列(有点像随机数),并非所有函数都可以,但有一个神奇的函数可以$ f(x)=(x^2+a)mod n $; $ a $ 可以指定也可以随机。

    这个序列显然是存在环的,如何检测环出现呢?

    方法一:floyd判环法

    floyd判环法:假如两个人$A、B$在环上走,如何知道已经走完一圈呢? 让$B$以$A$两倍的速度走,$B$第一次赶上$A$时,$B$至少走完一圈了

    设定$ x=y=x0 $的初始值,进行迭代,每次:$ x=f(x), y=f(f(y)) $ 即:$ x=x_i,y=x_{2i} $

    若$ gcd(x−y,n)=1 $,那么继续枚举下一对 $x,y$ 。

    若$ gcd(x−y,n)=n $,更换随机函数 f(x)f(x) ,重新进行算法。

    否者我们就找到了一个n的非平凡因子 $ d=gcd(x-y,n) $

    当 $x==y$时出现循环,此时$x-y=0$,$ gcd(x−y,n)=n $,即为2情况。

    LL pollardRho(LL n, int a){
        LL x=2,y=2,d=1;
        while(d==1){
            x=(x*x+a)%n;
            y=(y*y+a)%n;y=(y*y+a)%n;
            d=gcd(abs(x-y),n);
        }
        if(d==n) return pollardRho(n,a+1);
        return d;
    }

    方法二:brent判环法

    不同于floyd每次计算$x_i,x_{2i}$进行判断,brent每次只计算$x_i$,当$k$是2的方幂时,$y=x_k$,每次计算$d=gcd(x_k−y,n)$

    LL pollardRho(LL n, int a){
        LL x=2,y=2,d=1,k=0,i=1;
        while(d==1){
            ++k;
            x=(x*x+a)%n;
            d=gcd(abs(x-y),n);
            if(k==i){y=x;i<<=1;}
        }
        if(d==n)return pollardRho(n,a+1);
        return d;
    }

     求全部因子(结合miller-rabin测试)

    LL cnt,fact[100];
    LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
    LL pollardRho(LL n, int a){
        LL x=rand()%n,y=x,d=1,k=0,i=1;
        while(d==1){
            ++k;
            x=ksc(x,x,n)+a;if(x>=n)x-=n;
            d=gcd(x>y?x-y:y-x,n);
            if(k==i){y=x;i<<=1;}
        }
        if(d==n)return pollardRho(n,a+1);
        return d;
    }
    void findfac(LL n){
        if(millerRabin(n)){fact[++cnt]=n;return;}
        LL p=pollardRho(n,rand()%(n-1)+1);
        findfac(p);
        findfac(n/p); 
    }

    例题:POJ1811

    https://files-cdn.cnblogs.com/files/Doggu/Pollard-rho%E7%AE%97%E6%B3%95%E8%AF%A6%E8%A7%A3.pdf

    https://blog.csdn.net/qq_39972971/article/details/82346390

    https://www.cnblogs.com/book-book/p/6349362.html

  • 相关阅读:
    场景调研
    12.8
    12.7
    12.6
    12.5
    12.4
    12.3
    重启oracle数据库的操作方法
    oracle创建dblink方法
    SQL*Loader 详解
  • 原文地址:https://www.cnblogs.com/hjj1871984569/p/10363283.html
Copyright © 2020-2023  润新知