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

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

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

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

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

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

我们取$ k $ 个数$ x_1,x_2,x_3...x_k $,而取出的 $ k $ 个数中,$ \exist 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^{fact{1}{4}}$个数,这可能存不下。

Pollard's Rho 算法 

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

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

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

方法一:

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;
}

方法二:

不同于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;
}

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

猜你喜欢

转载自www.cnblogs.com/hjj1871984569/p/10363283.html