PollardRho 算法 ++快速乘++Miller Rabin判质数

NO.1

首先看快速乘

这里言简意赅,本蒟蒻用的是O(1)的 主要原理是:::=>>>x×y−⌊x×y/p⌋×p

inline ll ksc(ll x,ll y,ll p){
    ll z=(long double)x/p*y;
    ll res=(unsigned long long)x*y-(unsigned long long)z*p;
    return (res+p)%p;
}

NO.2

接下来是Miller Rabin判质数Miller Rabin判素数安利自己链接

NO.3(本文言简意赅,很好懂,but请小心食用)

PollardRho 算法用途:Pollard Rho 是一个很神奇的算法,用于在 O(n1/4) 的期望时间复杂度内计算合数n的某个非平凡因子(除了1和它本身以外能整除它的数)

First:

这个算法用的主要是随机思想,因为n有很多因数,所以用随机函数直接随机出n的因子复杂度O(n)(看RP吧)

Second:

我们需要优化一下,这时就可以用gcd来求。原理:一个合数(<n)它绝对存在一个质因子小于 sqrt(n) ,所以在 n 就存在至少 sqrt(n) 个数与 n 有大于一的公约数。于是我们随机的可能性就提高到了 O(sqrt(n))。简单来说就是随机出x,g=gcd(x,n),if(g>1) g|n;(g是n的因子)

Third:x^2+c || x=rand(),c=rand()

我们现在需要快速的找到一些数使得这些数与 n 有公约数。

定义y=x,x=x^2+c,g=gcd(abs(y-x),n);if(g>1) g|n;这样可以使复杂度降低到n^(1/4)。具体为什么,本人刚学只知道关于什么生日悖论。有兴趣自己看吧。

注意判环

x可能在某次(x^2+c)%n后与之前相等,

这里本人只给出倍增的方法::让y记住x的位置,然后x再跑当前跑过次数的一倍的次数。这样不断让y记住x的位置,x再往下跑,因为倍增所以当x跑到y时,已经跑完一个圈,并且也不会多跑太多(感性理解一下)
inline ll rho(ll n){
    ll x,y,c,g; rg i,j;
    x=y=rand(); c=rand();//初始化
    i=0,j=1;//倍增初始化
    while(++i){
        x=(ksc(x,x,n)+c)%n;//x只跑一次
        if(x==y)break;//跑完了一个环
        g=gcd(abs(y-x),n);//求gcd(注意绝对值)
        if(g>1)return g;
        if(i==j)y=x,j<<=1;//倍增的实现
    }
}
机智的小伙伴会发现这复杂度不近似于O(n(1/4)×log)吗

所以我们还有优化

我们发现我们在每一次生成操作中,乘法之后所模的数就是我们的 n ,而我们要求的就是 n 的某一个约数!也就是说我们现在的模数并不是一个质数!而根据取模的性质:如果模数和被模的数都含有一个公约数,那么这次模运算的结果必然也会是这个公约数的倍数!!!所以如果我们将若干个 (y−x) 乘到一起,因为中途模的是 n ,所以如果我的若干个 (y−x) 中有一个与n有公约数,最后的结果定然也会含有这个公约数!所以我们完全可以多算几次 (y−x) 的乘积在来求 gcd (一般连续算127次再求一次gcd(这个应该有大佬测试过了)),这样我们的复杂度就能降一个 log 级别,跑的飞快!!!!!

注意事项1.我们会等大概127次后再去gcd,然而我们有可能在生成时碰上一个环,我们有可能还没生成127次就跳出这个环了,这样就无法得出答案;

2.可能我们跑127次之后,所有 (y−x) 的乘积就变成了n的倍数(模 n 意义下得到 0 ),所以我们不能完全就只呆板的等127次在取模。

所以我们可以利用刚刚倍增的做法 分别在1 2 4 8 16 32 64.。。。的情况下求一下gcd;这样复杂度影响不大又可以解决上面问题。。。完结撒花!@#¥%……&*()

inline ll rho(ll p){//求出p的非平凡因子
    ll x,y,z,c,g; rg i,j;//先摆出来(z用来存(y-x)的乘积)
    while(1){//保证一定求出一个因子来
        y=x=rand()%p;//随机初始化
        z=1; c=rand()%p;//初始化
        i=0,j=1;//倍增初始化
        while(++i){//开始玄学生成
            x=(ksc(x,x,p)+c)%p;//可能要用快速乘
            z=ksc(z,Abs(y-x),p);//我们将每一次的(y-x)都累乘起来
            if(x==y||!z)break;//如果跑完了环就再换一组试试(注意当z=0时,继续下去是没意义的)
            if(!(i%127)||i==j){//我们不仅在等127次之后gcd我们还会倍增的来gcd
                g=gcd(z,p);
                if(g>1)return g;
                if(i==j)y=x,j<<=1;//维护倍增正确性,并判环(一箭双雕)
            }
        }
    }
}

☎博主撰文不易,转载还请注明出处;如有问题还望指教œ?œœšºõ2bìÖÿ(-。-)ç(⊙o⊙)?wow~ ⊙o⊙

posted @ 2020-11-17 14:57  *LZX*  阅读(148)  评论(0编辑  收藏  举报