初学Pollard Rho算法
前言
\(Pollard\ Rho\)是一个著名的大数质因数分解算法,它的实现基于一个神奇的算法:\(MillerRabin\)素数测试(关于\(MillerRabin\),可以参考这篇博客:初学MillerRabin素数测试)。
期望下,\(Pollard\ Rho\)算法可以达到极快的复杂度。
核心思想
在\(ZJOI2019Day1\)讲课期间,它是被\(CQZ\)神仙作为随机算法内的一部分来进行介绍的。
由此可见,其核心思想便是随机二字。
操作流程
首先,我们先用\(MillerRabin\)判断当前数\(x\)是否为质数,若是,则可直接统计信息并退出函数
否则,我们考虑,如果能找到一个数\(s\)使得\(1<gcd(s,x)<x\),则\(x\)必然可以被分成\(gcd(s,x)\)和\(\frac x{gcd(s,x)}\)两部分,接下来递归处理这两部分即可。
那么我们要找的,就是一个符合条件的\(s\)。
而找的过程利用了随机。
我们随机出一个\(1\sim x-1\)范围内的数\(v_0\),然后,不断计算\(v_i=(v_{i-1}*v_{i-1}+t)\%x\)(\(t\)为一个自己设定的常数)。
则我们每次判断\(d=gcd(abs(v_i-v_0),x)\)是否大于\(1\)且不等于\(x\)本身,若满足则可直接返回\(d\)。
由于\(v_i\)最终肯定会形成环,而在形成环的时候,我们就无法继续操作了,因此当\(v_i=v_0\),我们就可以退出函数并返回\(x\)本身,表示分解失败。
对于分解失败的情况,我们可以调整\(t\)并重新进行分解。
根据生日悖论,形成的期望环长为\(O(\sqrt x)\),因此复杂度得以保证。
但是,光这样依然不够,我们还需要加优化。
优化:路径倍长
考虑到如果对于每个\(v_i\)都要计算一遍\(gcd\),显然很慢。
于是,就会想到每隔一段时间将这些数一起进行一次\(gcd\)。
而隔的时间如何确定呢?
我们可以倍增。
用一个变量\(s\)统计\(abs(v_i-v_0)\)之积并向\(n\)取模,因为取模不会改变\(gcd\)。
如果某一时刻\(s\)变成了\(0\),则分解失败,退出函数并返回\(x\)本身。
然后每隔\(2^k\)个数,我们计算\(gcd(s,x)\)是否大于\(1\)且小于\(x\),然后重新把\(v_0\)设置为当前的\(v_i\)。
这样一来,复杂度就得到了大大优化。
代码(板子题)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define RL Reg LL
#define Con const
#define CI Con int&
#define CL Con LL&
#define I inline
#define W while
#define LL long long
#define Gmax(x,y) (x<(y)&&(x=(y)))
#define abs(x) ((x)<0?-(x):(x))
#define hl_AK_NOI true
using namespace std;
I LL Qmul(CL x,CL y,CL X)//快速乘
{
RL k=(1.0L*x*y)/X,t=x*y-k*X;
t-=X;W(t<0) t+=X;return t;
}
class MillerRabin//MillerRabin判素数板子
{
private:
#define Pcnt 12
Con int P[Pcnt]={2,3,5,7,11,13,17,19,61,2333,4567,24251};
I LL Qpow(RL x,RL y,CL X)
{
RL t=1;W(y) y&1&&(t=Qmul(t,x,X)),x=Qmul(x,x,X),y>>=1;
return t;
}
I bool Check(CL x,CI p)
{
if(!(x%p)||Qpow(p%x,x-1,x)^1) return false;
RL k=x-1,t;W(!(k&1))
{
if((t=Qpow(p%x,k>>=1,x))^1&&t^(x-1)) return false;
if(!(t^(x-1))) return true;
}return true;
}
public:
bool IsPrime(CL x)
{
if(x<2) return false;
for(RI i=0;i^Pcnt;++i) {if(!(x^P[i])) return true;if(!Check(x,P[i])) return false;}
return true;
}
};
class PollardRho//PollardRho分解质因数
{
private:
#define Rand(x) (1LL*rand()*rand()*rand()*rand()%(x)+1)
LL ans;MillerRabin MR;
I LL gcd(CL x,CL y) {return y?gcd(y,x%y):x;}//求gcd
I LL Work(CL x,CI y)//分解
{
RI t=0,k=1;RL v0=Rand(x-1),v=v0,d,s=1;W(hl_AK_NOI)//初始化随机一个v0
{
if(v=(Qmul(v,v,x)+y)%x,s=Qmul(s,abs(v-v0),x),!(v^v0)||!s) return x;//计算当前v,统计乘积,判断是否分解失败
if(++t==k) {if((d=gcd(s,x))^1) return d;v0=v,k<<=1;}//倍增
}
}
I void Resolve(RL x,RI t)//分解
{
if(!(x^1)||x<=ans) return;if(MR.IsPrime(x)) return (void)Gmax(ans,x);//先进行特判
RL y=x;W((y=Work(x,t--))==x);W(!(x%y)) x/=y;Resolve(x,t),Resolve(y,t);//找到一个因数y,然后分解(注意除尽)
}
public:
I PollardRho() {srand(20050521);}//初始化随机种子
I LL GetMax(CL x) {return ans=0,Resolve(x,302627441),ans;}//求答案
}P;
int main()
{
RI Ttot;RL n,res;scanf("%d",&Ttot);
W(Ttot--) scanf("%lld",&n),(res=P.GetMax(n))^n?printf("%lld\n",res):puts("Prime");//输出
return 0;
}
初学Pollard Rho算法的更多相关文章
- Pollard rho算法+Miller Rabin算法 BZOJ 3668 Rabin-Miller算法
BZOJ 3667: Rabin-Miller算法 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 1044 Solved: 322[Submit][ ...
- Pollard Rho 算法简介
\(\text{update 2019.8.18}\) 由于本人将大部分精力花在了cnblogs上,而不是洛谷博客,评论区提出的一些问题直到今天才解决. 下面给出的Pollard Rho函数已给出散点 ...
- Pollard Rho算法浅谈
Pollard Rho介绍 Pollard Rho算法是Pollard[1]在1975年[2]发明的一种将大整数因数分解的算法 其中Pollard来源于发明者Pollard的姓,Rho则来自内部伪随机 ...
- Miller Rabin素数检测与Pollard Rho算法
一些前置知识可以看一下我的联赛前数学知识 如何判断一个数是否为质数 方法一:试除法 扫描\(2\sim \sqrt{n}\)之间的所有整数,依次检查它们能否整除\(n\),若都不能整除,则\(n\)是 ...
- 大整数分解质因数(Pollard rho算法)
#include <iostream> #include <cstring> #include <cstdlib> #include <stdio.h> ...
- BZOJ 5330 Luogu P4607 [SDOI2018]反回文串 (莫比乌斯反演、Pollard Rho算法)
题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=5330 (Luogu) https://www.luogu.org/prob ...
- 【快速因数分解】Pollard's Rho 算法
Pollard-Rho 是一个很神奇的算法,用于在 $O(n^{\frac{1}4}) $的期望时间复杂度内计算合数 n 的某个非平凡因子(除了1和它本身以外能整除它的数).事书上给出的复杂度是 \( ...
- Pollard Rho因子分解算法
有一类问题,要求我们将一个正整数x,分解为两个非平凡因子(平凡因子为1与x)的乘积x=ab. 显然我们需要先检测x是否为素数(如果是素数将无解),可以使用Miller-Rabin算法来进行测试. Po ...
- 【Luogu】P4358密钥破解(Pollard Rho)
题目链接 容易发现如果我们求出p和q这题就差不多快变成一个sb题了. 于是我们就用Pollard Rho算法进行大数分解. 至于这个算法的原理,emmm 其实也不是很清楚啦 #include<c ...
随机推荐
- 转 Nmon 监控生成数据文件字段的介绍
##发现nomon 一个好用的功能 数据透视图 PIVOTCHART:这些参数被用来构建数据透视图.所需的参数:Sheetname,PageField,rowfield,columnfield,Dat ...
- C#中Using里使用单例的问题
又给自己挖了一个坑跳进去. KafkaManager使用单例模型获取到一个producer,然而自己代码里用的时候加了一个using using (var producer = KafkaManage ...
- Angular4+NodeJs+MySQL 入门-05 接口调用
接口调用 今天讲一下,如果在前端页面上通过调用后台接口,返回来的数据.把前面的几章结合起来. 这里所有用的代码在 https://github.com/xiaotuni/angular-map-htt ...
- 基于setTimeout制作滚动广告板
很多网站在其门户页面的上方正中央都会放置一个滚动广告板,用于显示一些推荐信息,用户点击即可进入浏览.比较常见的就是各个公司的官网,电商网站的首页等. 下面是天猫的滚动广告板截图. 其实,不需要借助于什 ...
- c#输入方法名来调用方法(反射)
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Sy ...
- SpringBoot | 第二十九章:Dubbo的集成和使用
前言 今年年初时,阿里巴巴开源的高性能服务框架dubbo又开始了新一轮的更新,还加入了Apache孵化器.原先项目使用了spring cloud之后,已经比较少用dubbo.目前又抽调回原来的行业应用 ...
- Codeforces 975D. Ghosts
Description 给出一条直线 \(a*x+b\) 上的 \(n\) 个点,每一个点有一个速度 \((v_x,v_y)\),求 \(T=[-oo,oo]\) 相交的次数乘以 \(2\) 题面 S ...
- 关于日常使用Azure MySQL中遇到的连接问题以及排查方法分享
由于防火墙问题,TCP keep alive 问题,以及 MySQL 自身的参数问题这三个在使用中比较常见,所以今天就分享下自己找到的排查方法. 今天先聊一聊防火墙问题 大多数人在第一次创建 MySQ ...
- 网站部署中遇到的问题-编译器错误信息: CS0016
问题描述: 访问站点出现错误win7 x64+iis7.5 配置错误:CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framework64\v4.0.30319\ ...
- hdu 2196 叶子节点最长距离(树DP)
http://www.cnblogs.com/kuangbin/archive/2012/08/28/2659915.html 求每个节点到叶子节点的最长距离 需要保存每个节点到叶子节点距离的最大值和 ...