数论 Pollard_Rho算法

1.1作用

Pollard_Rho算法解决大数的质因数分解。又是一个玄学算法..

2.1 试除法

我们的任务是对一个数字n进行质因数分解。可以发现,n的因数将会对称的分布在[1,sqrt(n)],和[sqrt(n),n]两个区间中,我们只需对前者扫一遍,即可求出所有的质因数,复杂度为\(0(\sqrt(n))\)

但是,假如数据范围是longlong范围呢?1e18呢?试除法似乎有点捉襟见肘...

2.2 一个显而易见的错误随机方法

emm,很明显,完整的扫一遍是不可能的,尝试随机一下。假设数字为在1e18范围内充斥着两个质因数,我们随机来一发,会有多大的几率中奖?的确,我们有一定的概率会得到一个因数,但概率显而易见不在我们可以接受的范围内。

3.1 生日悖论

生日悖论,指如果一个房间里有23个或23个以上的人,那么至少有两个人的生日相同的概率要大于50%。这就意味着在一个典型的标准小学班级(30人)中,存在两人生日相同的可能性更高。对于60或者更多的人,这种概率要大于99%。

这个生日悖论,条件显而易见,证明方法显而易见,只是因为与常识有所违背,所以称之为"悖论"。

这个悖论告诉我们的精华在于:在[1,n]内的数字中随机抽取数字,使之与指定数字p相同,抽取\(\sqrt(n)\)次便有了50%的概率;抽取次数越高,概率越可观。即,在范围内抽出数字使之符合期望是一件可以实现的事情。

3.2 基于生日悖论的随机方法改进

这样子看来,虽然随机一遍成功的概率微乎其微,但通过多次随机,其期望步骤在可接受范围内。

但是,眼前还有很多问题没有解决

[1] 怎么随机出合适的数字?直接随机?

[2] 怎么合理的判断是否是因数?

4.1 Pollard_Rho算法

对于上述问题算法,Pollard_Rho算法提出了一个切实可行的方法。

引出一个函数如下:

\[f(n)=(n^2+c) \quad mod\ x
\]

c是一个随机的常数,范围在[1,x-1];x是当前进行质因数分解的数字。

从0开始,代入函数,并将结果再次代入函数,会顺序地得到一个数列a[..]。由于函数的特性,在一定范围内可以保证数列的随机性。数列中相邻两个数字做差,就可以得到一个随机数字n。求d=gcd(n,x),倘若d大于1,d便是x的一个因数。

由于函数的某种玄学特性,这个做法相比普通随机可以节省大量时间。具体证明就..鸽了..╰( ̄ω ̄o)

此时,我们得到了x的一个因数d,但这显然是不够的。我们需要将d和x/d继续分解,直到全部分解为质因数。

4.2 floyd判环

你知道为什么这个算法叫\(Pollard \quad \rho\)吗?(罗马字母\(\rho\)发音rho)因为通过这个函数得到数列可能会存在循环节,倘若出现了循环节,我们将反反复复进行大量无用尝试,而无法得到结果。因此,我们需要一个有效的判环操作。

通过生日悖论可知,这个环的期望长度在\(\sqrt n\)级别,但是我还是不会证明

floyd判环的思想在于设两个指针,让两个指针同时以不同的速率进行运动,这样的话倘若两个指针进入了环,期望只需要\(\sqrt n\)步,两个指针便会再次重逢,此时退出循环。枚举不同的c,并再次尝试。

既然我们已经有了两个指针了,就不再拘泥于必须要相邻的两个数字。两个指针的结果作差取绝对值即可。

4.3 基于floyd判环补充、生日悖论佐证的随机算法

至此,Pollard_Rho算法的基础理论,流程框架已经完整地展现出来了。

[1] 先用Millar_Rabin判断是否为质数,如果是质数说明已经到头;否则进行接下来的操作。

[2] 用函数生成数列,得到随机数n,在gcd(n,x)>1时,得到一个因数gcd(n,x)

[3] 倘若因为不合适的c导致了数列出现了循环节,利用floyd判环,及时退出即可

[42] 将x拆分为x和x/gcd(n,x),递归下去

5.1 路径倍增优化

求解一次gcd的复杂度是\(o(log\ n)\),大量求解gcd必然会降低效率。因此我们要慎重使用gcd

倘若使用频率过低,可能会出现出现了答案却不能及时退出;使用频率过高,效率就会显著受到影响

那么,就倍增路径!就是这么直接( ¯(∞)¯ )

每\(2^i\)步判断一次gcd,在此之前,递乘每一次的结果。由于某种特殊神秘的性质,对结果取模并不会对gcd产生影响。因此可以放心地取模

5.2 127优化

这个,从洛谷上看到的。尝试了一下发现确实虽然不愿意承认有实际效果。(ac掉最后一个tle点)

方法是:每127步求一遍gcd。

有点难以解释..127除了是质数以外,似乎没有其它特殊的性质。就当作一个玄学优化技巧吧。

6.1 代码

在洛谷上有Pollard_Rho的板子题,代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull; const int MAX=1e6+5,TOP=1e4;
bool vis[MAX]; int prime[MAX];
ll max_factor; int T; ll n; ll read();
void oula();
ll qsm(ll a,ll k,ll m);
ll qsc(ll a,ll b,ll m);
bool millar_rabin(ll);
void pollard_rho(ll);
ll frac(ll);
ll func(ll,ll,ll);
ll gcd(ll a,ll b); int main(){
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif oula(); scanf("%d",&T);
while(T--){
n=read();
max_factor=0;
pollard_rho(n);
if(max_factor==n) printf("Prime\n");
else printf("%lld\n",max_factor);
} return 0;
} ll read(){
char tmp=getchar(); ll sum=0; bool flag=false;
while(tmp<'0'||tmp>'9'){
if(tmp=='-') flag=true;
tmp=getchar();
}
while(tmp>='0'&&tmp<='9'){
sum=(sum<<1)+(sum<<3)+tmp-'0';
tmp=getchar();
}
return flag?-sum:sum;
} void oula(){
for(int i=2;i<=TOP;++i){
if(!vis[i]) prime[++prime[0]]=i;
for(int j=1;j<=prime[0]&&prime[j]*i<=TOP;++j){
vis[prime[j]*i]=true;
if(i%prime[j]==0) break;
}
}
} ll qsm(ll a,ll k,ll m){
ll ans=1,base=a,mod=m;
while(k){
// if(k&1) ans=ans*base%mod;
if(k&1) ans=qsc(ans,base,mod);
// base=base*base%mod;
base=qsc(base,base,mod);
k>>=1;
}
return ans;
} ll qsc(ll a,ll b,ll m){
// ll ans=0,base=a,mod=m;
// while(b){
// if(b&1) ans=(ans+base)%mod;
// base=(base+base)%mod;
// b>>=1;
// }
// return ans; ll z=(ld)a/m*b;
ll res=(ull)a*b-(ull)z*m;
return (res+m)%m; return ((ull)a*b-(ull)((ld)a/m*b*b))%m;
} bool millar_rabin(ll x){
if(x==2) return true;
if(!(x&1)||x==0||x==1) return false;
ll s=0,t=x-1;
while(!(t&1)) s++,t>>=1;
for(int p=1;p<=30&&prime[p]<x;++p){
ll b=qsm((ll)prime[p],t,x),k;
for(ll i=1;i<=s;++i){
k=qsc(b,b,x);
if(k==1&&b!=1&&b!=x-1) return false;
b=k;
}
if(b!=1) return false;
}
return true;
} void pollard_rho(ll x){
if(x==1) {max_factor=1; return;}
if(millar_rabin(x)) {max_factor=max(x,max_factor); return;}
ll p;
do{
p=frac(x);
}while(p>=x);
while(x%p==0) x/=p;
if(x!=1) pollard_rho(x); pollard_rho(p);
} ll frac(ll x){
ll s,t,c,d;
c=rand()%(x-1)+1;
s=0; t=func(0,c,x);
ll goal=1,step=0,val=1;
while(s!=t){
step++;
val=qsc(val,abs(s-t),x);
if(step==goal){
d=gcd(val,x);
if(d>1) return d;
goal<<=1ll;
}
s=func(s,c,x);
t=func(func(t,c,x),c,x);
}
return x;
} ll func(ll x,ll c,ll mod){
return (qsc(x,x,mod)+c)%mod;
} ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}

7.1 引用资料

一个非常有用的pdf

Pollard_Rho算法的更多相关文章

  1. 数论 - Miller_Rabin素数测试 + pollard_rho算法分解质因数 ---- poj 1811 : Prime Test

    Prime Test Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 29046   Accepted: 7342 Case ...

  2. 【转】大素数判断和素因子分解【miller-rabin和Pollard_rho算法】

    集训队有人提到这个算法,就学习一下,如果用到可以直接贴模板,例题:POJ 1811 转自:http://www.cnblogs.com/kuangbin/archive/2012/08/19/2646 ...

  3. 数学#素数判定Miller_Rabin+大数因数分解Pollard_rho算法 POJ 1811&2429

    素数判定Miller_Rabin算法详解: http://blog.csdn.net/maxichu/article/details/45458569 大数因数分解Pollard_rho算法详解: h ...

  4. Miller_Rabbin算法判断大素数,Pollard_rho算法进行质因素分解

    Miller-rabin算法是一个用来快速判断一个正整数是否为素数的算法.它利用了费马小定理,即:如果p是质数,且a,p互质,那么a^(p-1) mod p恒等于1.也就是对于所有小于p的正整数a来说 ...

  5. pollard_rho 算法进行质因数分解

    //************************************************ //pollard_rho 算法进行质因数分解 //*********************** ...

  6. 数学:随机素数测试(Miller_Rabin算法)和求整数素因子(Pollard_rho算法)

    POJ1811 给一个大数,判断是否是素数,如果不是素数,打印出它的最小质因数 随机素数测试(Miller_Rabin算法) 求整数素因子(Pollard_rho算法) 科技题 #include< ...

  7. 大数因式分解 Pollard_rho 算法详解

    给你一个大数n,将它分解它的质因子的乘积的形式. 首先需要了解Miller_rabin判断一个数是否是素数 大数分解最简单的思想也是试除法,这里就不再展示代码了,就是从2到sqrt(n),一个一个的试 ...

  8. 大素数判断和素因子分解(miller-rabin,Pollard_rho算法) 玄学快

    大数因数分解Pollard_rho 算法 复杂度o^(1/4) #include <iostream> #include <cstdio> #include <algor ...

  9. 大素数判断和素因子分解(miller-rabin,Pollard_rho算法)

    #include<stdio.h> #include<string.h> #include<stdlib.h> #include<time.h> #in ...

  10. Pollard_rho算法进行质因素分解

    Pollard_rho算法进行质因素分解要依赖于Miller_Rabbin算法判断大素数,没有学过的可以看一下,也可以当成模板来用 讲一下Pollard_rho算法思想: 求n的质因子的基本过程是,先 ...

随机推荐

  1. Bootstrap中的dropdown、下拉选择框、dropdown-toggle

    注意:如果您想要单独引用该插件的功能,那么您需要引用 dropdown.js.可以引用 bootstrap.js 或压缩版的 bootstrap.min.js. <!DOCTYPE html&g ...

  2. 【JavaWeb】学习笔记——Ajax、Axios

    Ajax Ajax 介绍 AJAX(Asynchronous JavaScript And XML):异步的JavaScript 和 XML AJAX 的作用: 与服务器进行数据交换:通过AJAX可以 ...

  3. k8s机器群扩容问题

    今天遇到了一个很奇葩的问题.公司新人吧k8s集权扩容完后,发现服务器上的磁盘没有做分区2T磁盘没有做任何动作 把两台slave节点扩容上去的节点弄到了/目录.由于是生产环境情况比较特殊并没通过kube ...

  4. ThreadPoolExecutor BlockingQueue讲解

    有四种常用阻塞队列策略: 1.直接拒绝:(Direct Handoffs) 一个好的工作队列应该是不缓存任务,而是直接交给线程处理,就如SynchronousQueue一样.一个任务将会入队失败,如果 ...

  5. Optional用法与争议点

    原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 要说Java中什么异常最容易出现,我想NullPointerException一定当仁不让,为了解决这种null值 ...

  6. 论文笔记 - GRAD-MATCH: A Gradient Matching Based Data Subset Selection For Efficient Learning

    Analysis Coreset 是带有权重的数据子集,目的是在某个方面模拟完整数据的表现(例如损失函数的梯度,既可以是在训练数据上的损失,也可以是在验证数据上的损失): 给出优化目标的定义: $w^ ...

  7. 20、求解从1到20000内的所有水仙花数:每位数字的n次方之和等于其本身,n是这个数的位数。

    /* 求解从1到20000内的所有水仙花数:每位数字的n次方之和等于其本身,n是这个数的位数. 共五位数,设置一个数组用来保存数字的每一位,数组的有效长度就是该数的位数.最后读取数组的每位数字来判断水 ...

  8. Linux禁止摄像头自动曝光(手动调节曝光)

    前言 很多摄像头具有自动曝光的功能,例如在较暗的调节下,提高曝光率,在较亮的调节下降低曝光.下面简单介绍在linux平台俩种方式来修改自动曝光. 软件调节(图形化界面) 安装qv4l2 sudo ap ...

  9. docker给已存在的容器添加或修改端口映射

    简述: 这几天研究了一下docker, 发现建立完一个容器后不能增加端口映射了,因为 docker run -p 有 -p 参数,但是 docker start 没有 -p 参数,让我很苦恼,无奈谷歌 ...

  10. Spring之SpringContext

    一.概述 1.Spring Context概念 创建上下文并将BeanPostProcessor加载到spring 2.Spring Application Context概念 Spring通过应用上 ...