Miller_Rabbin&&Pollard_Rho 学习笔记

Intro

首先我们考虑这样一个问题

给定一个正整数 \(p \ (p<=1e8)\),请判断它是不是质数

妈妈我会试除法!

于是,我们枚举 \(\sqrt p\) 以内的所有数,就可以非常轻松地得到正确答案。

贴一小段代码

bool check(int n)
{
if(n==1) return false;
for(int i=2;i*i<=n;++i)
if(!(n%i)) return false;
return true;
}

\(Extra\):给定 \(p\ (p<=1e5)\) 个正整数 \(p\ (p<=1e8)\) ,请判断它是不是质数

妈妈我会埃氏筛!

所谓筛法,就是利用了一条最最基本的原理:素数的倍数一定是合数,于是,我们便可以在一定数据范围之内来解决多次询问一个数是否为素数的问题

埃氏筛便是基于这个最简单的思想

时间复杂度约为\(O(nlog_{2}n)\)

再贴一小段代码

void prime()
{
memset(isprime,0,sizeof isprime);
for(int i=2;i<=n;i++)
if(isprime[i]==0)
for(int j=i+i;j<=n;j+=i)
isprime[j]=1;
}

\(Extra^{2}\):给定 \(p\ (p<=1e7)\) 个正整数 \(p \ (p<=1e8)\),请判断它们是不是质数

妈妈我有信仰,我能写出常数极为优秀的埃氏筛

这显然是不现实的,那可以怎样解决这个问题呢?

爸爸我会欧拉筛!

我们会发现,在用埃氏筛解决问题的时候,我们仍然进行了一些不必要的操作,比如\(30\),在程序运行中我们用了\(2,3,5\)三个素数来证明其为合数,这显然是十分不合常理的。

所以我们考虑对其进行优化。

我们考虑,对于每一对\((i,prime[j])\), 显然$i*prime[j] $为合数,我们将其筛去

当 $ i \ mod \ prime[j] =0 $ 时就说明剩余的情况,我们会在以后考虑到,因为每一个合数都可以分解为一个合数(或一个质数)和一个质数的乘积,这样就可以避免重复考虑

时间复杂度约为 \(O(n)\)

再贴一小段代码

void prime()
{
memset(isprime,0,sizeof isprime);
for(int i=2;i<=n;i++)
{
if(isprime[i]==0)
++cnt,prime[t]=i;
for(int j=1;j<=t&&i*prime[j]<=n;++j)
{
isprime[i*prime[j]]=1;
if(!(i%prime[j])) break;
}
}
}

\(Extra^{3}\):给定 \(p\ (p<=1e4)\) 个正整数 \(p\ (p<=1e16)\),请判断它们是不是质数

好像没辙了

Miller-Rabbin 算法

所谓 \(\texttt{Miller-Rabbin}\) 素性测试算法,就是在极短的的时间内,通过一种玄学科学的判断方法,使得判断出错的概率尽可能小。也就是说,这是一个正确率可控,但不稳定的算法

但为什么要学它呢?

至少,在OI界内够用嘛

因为,我们可以通过人为的操作,将其错误率降到我们可以接受的范围内。


前置芝士:欧拉定理

即当 \(p\) 是质数时

\[a^{\varphi (p)}\equiv 1 (mod \ p)
\]

由 \(\varphi (p)=p-1\) 得

\[a^{p-1}\equiv 1 (mod \ p)
\]

于是,既然当 \(p\) 是质数时,\(a^{p-1}\equiv 1 (mod \ p)\) 成立

那么,当 \(a^{p-1}\equiv 1 (mod \ p)\) 成立时,\(p\) 是否为质数呢?

显然不是!!!

那么,我们是否能够可以尝试一种方法,将一个数进行多次测试,这就是这种测试方法的一个初级想法。

但是,是否存在一些合数,能够通过所有的测试呢?

答案是肯定的。这样的书被人们称为\(\texttt{Carmichael}\)数,如 \(561,1105,1729\) ,有兴趣可以点击此链接

所以说,我们有没有一种办法,能够使得正确率进一步提高呢?

答案依然是肯定的。


二次探测

如果\(p\)为质数,且

\[x^2\equiv 1\pmod{p}
\]

那么 $ x=1 \ or \ p-1 $。

这个应该是显然吧,移项直接就可以得到。

然后,我们就可以利用这一个性质来完成 \(\texttt{Miller-Rabbin}\) 素性测试。


具体做法:

  • 将 \(p-1\) 提取出所有 \(2\) 的因数,假设有 \(num\) 个。设剩下的部分为 \(tot\)。

  • 枚举(或随机)一个底数 \(a\) 并计算 \(r=a^{tot}\pmod p\)。

  • 将 \(r\) 连续平方 \(num\) 次。如果没有出现过 \(p-1\) ,那么 \(p\) 未通过二次探测,不是质数。

  • 否则,若已经测试完毕,则跳出。否则回到第二步。

个人常用的模数:\(3,5,7,11,13,37,79,97\) (还是挺好记的吧)

进行一次二次探测的时间复杂度为为 \(O(\log_2n)\)。

所以测试一个数是否为素数的时间最坏为 \(O(T\log_2n)\),其中 \(T\) 为测试次数。

贴代码

typedef long long ll;
bool miller_rabbin(ll x,ll a,ll d)
{
if(x==1||(!(x&1))) return 0;
if(x==2) return 1;
while(!(d&1))
d>>=1;
ll t=ksm(a,d,x);
while(d!=x-1&&t!=1&&t!=x-1)
{
t=ksc(t,t,x);
d<<=1;
}
return t==x-1||(d&1)==1;
}
bool solve(ll n)
{
for(int i=1;i<=6;++i)
{
if(n==te[i]) return 1;
if(!miller(n,te[i],n-1)) return 0;
}
return 1;
}

Part II


Pollard-Rho


A Brief introduction

\(Pollard-Rho\)是一个基于随机算法的大整数分解算法,可以在较短时间内求出其因数。


考虑这样一个问题

从\(\left [2,n \right ]\)中随机一个数字,求其为n的约数的概率。

这个概率显然是很低的,不符合我们的期望

我们考虑优化这个算法

Birthday Trick (生日悖论)

我们稍微修改一下这个问题:

从[1,1000]中随机选取两个数  x 和 y,x−y=42 (x≠y) 的概率是多少?

能够粗略地算出,此时的概率大约为\(\frac{1}{500}\)。

如果我们不再坚持仅选取1个数并且这个数必须为42,而是能够选取2个数并且他们的差刚好等于42,那么,成功的概率被提高了。

如果我们在[1,1000]中选取 k 个数 x1,……,xk, 

取得的k个数中满足xi−xj=42的概率是多少呢?

大约在 k=30 的时候,成功的概率已经超过一半。 

我们有一个大区间[1,1000],但是仅仅生成约 30 个随机数就让我们成功的概率超过了一半,大约在 k=100 的时候,我们几乎可以确保我们是成功的。这是一个非常重要的观察, 它被称为生日悖论

以上摘自某国外论文


于是,我们就可以通过这样一个方法来大幅度的提高程序效率

为了使复杂度较稳定,我们可以使随机数不那么随机

根据\(f(x)=x^2+c\) 来随机生成,复杂度较优

但是这样生成可能有环出现,于是有两种方法可以来解决这个问题

i.floyd法

我们可以设置两个变量,像追击问题那样,让一个变量以另一个变量的二倍速来扩展,这样,当他们再一次相等时,至少跑过了一圈。

ii.倍增优化法

暂时略

然后关于本代码,由于为了通过Luogu上的毒瘤测试点,加了非常多的玄学优化,在此暂时不做叙述。

留坑,待填

贴代码

ll f(ll n,ll c,ll md)
{
return (ksc(n,n,md)+c)%md;
}
ll ans=0;
ll pollard_rho(ll n)
{
ll w=rand()%(n-1)+1;
ll a,b;
a=b=rand()%(n-1)+1;
ll i=0,j=1;
ll p=1;
ll z=1;
while(++i)
{
a=f(a,w,n);
if(b>a)p=b-a;
else p=a-b;
z=ksc(z,p,n);
if(a==b||(!z)) return n;
if(!(i%667)||i==j)
{
p=gcd(z,n);
if(p>1) return p;
if(i==j)
b=a,j<<=1;
}
}
return n;
}
void solve(ll n)//求一个数的最大质因数
{
if(n==1) return ;
if(n<ans) return ;
if(miller_rabbin(n))
{
ans=max(ans,n);
return;
}
ll t=n;
while(t==n)
t=pollard_rho(t);
solve(t);
solve(n/t);
}

Miller_Rabbin&&Pollard_Rho 学习笔记的更多相关文章

  1. 数论算法 剩余系相关 学习笔记 (基础回顾,(ex)CRT,(ex)lucas,(ex)BSGS,原根与指标入门,高次剩余,Miller_Rabin+Pollard_Rho)

    注:转载本文须标明出处. 原文链接https://www.cnblogs.com/zhouzhendong/p/Number-theory.html 数论算法 剩余系相关 学习笔记 (基础回顾,(ex ...

  2. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  3. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  4. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  5. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  6. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  7. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  8. CSS学习笔记

    CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...

  9. HTML学习笔记

    HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...

随机推荐

  1. 18-09-20,String 与 StringBuilder (StringBuffer)

    1.其一 在运行速度方面:StringBuilder > StringBuffer > String 上实例 class Program { static void Main(string ...

  2. 程序员50题(JS版本)(八)

    程序36:有n个人围成一圈,顺序排号.从第一个人开始报数(从1到3报数),凡报到3的人推出圈子,问最后留下的是原来第几号的那位 var n=20; var arr=[]; for(var i=0;i& ...

  3. JavaScript局部变量变量和函数命名提升

    之前接触了一些javascript局部变量命名提升的问题但是一直没有总结今天特地好好总结一下 变量提升 一个变量的作用域是程序源代码中定义的这个变量的区域.全局变量拥有全局作用域,在javascrip ...

  4. Skyline Terra Explorer6.6弹出窗口实现复制功能

    前段时间继续下来的基于Skyline的B/S项目,是基于Terra Explorer6.6实现的.项目中涉及到基于三维模型查询设备编码等操作,从用户友好角度来讲,查询到的设备编码应该要支持复制,方便用 ...

  5. 自动化测试 Appium之Python运行环境搭建 Part2

    Appium之Python运行环境搭建 Part2 by:授客 QQ:1033553122 实践环境 参见 Appium之Python运行环境搭建 Part1 环境部署 1.安装Android SDK ...

  6. Netty 核心内容之 编解码器

    原文链接 Netty 核心内容之 编解码器 代码仓库地址 编解码器 我认为Netty 最棒的一点就是Netty 设计的编解码链,这一优秀的设计,可以很方便的实现二进制流->ByteBuf-> ...

  7. HTTP中GET和POST的区别主要是那些,面试中可以加分的该说那些?

    面试回答: GET请求在URL中传送的参数是有长度限制的,而POST没有. GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息. GET参数通过URL传递,POST放在Re ...

  8. SQL Server数据库文件与文件组总结

    文件和文件组概念 关于文件与文件组,简单概括如下,详情请参考官方文档"数据库文件和文件组Database Files and Filegroups"或更多相关资料: 数据文件概念: ...

  9. 爬虫技术实现空间相册采集器V.0.0.1版本

    一.    功能需求分析: 在很多时候我们需要做这样一个事情:我们想把我们QQ空间上的相册高清图像下载下来,怎么做?到网上找软件?答案是否定的,理由之一:网上很多软件不知有没有病毒,第二它有可能捆了很 ...

  10. 周一04.3流程控制while循环

    #循环就是重复做某件事 1.条件循环:while,语法如下 while 条件: # 循环体 # 如果条件为真,那么循环体则执行,执行完毕后再次循环,重新判断条件... # 如果条件为假,那么循环体不执 ...