Miller_Rabbin&&Pollard_Rho 学习笔记
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\) 是质数时
\]
由 \(\varphi (p)=p-1\) 得
\]
于是,既然当 \(p\) 是质数时,\(a^{p-1}\equiv 1 (mod \ p)\) 成立
那么,当 \(a^{p-1}\equiv 1 (mod \ p)\) 成立时,\(p\) 是否为质数呢?
显然不是!!!
那么,我们是否能够可以尝试一种方法,将一个数进行多次测试,这就是这种测试方法的一个初级想法。
但是,是否存在一些合数,能够通过所有的测试呢?
答案是肯定的。这样的书被人们称为\(\texttt{Carmichael}\)数,如 \(561,1105,1729\) ,有兴趣可以点击此链接。
所以说,我们有没有一种办法,能够使得正确率进一步提高呢?
答案依然是肯定的。
二次探测
如果\(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 学习笔记的更多相关文章
- 数论算法 剩余系相关 学习笔记 (基础回顾,(ex)CRT,(ex)lucas,(ex)BSGS,原根与指标入门,高次剩余,Miller_Rabin+Pollard_Rho)
注:转载本文须标明出处. 原文链接https://www.cnblogs.com/zhouzhendong/p/Number-theory.html 数论算法 剩余系相关 学习笔记 (基础回顾,(ex ...
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
随机推荐
- 学JAVA第十八天,接口与抽象类进一步加深
昨天老师讲了建网站,还要交钱买东西的,所以就没写,今天讲了接口与抽象类进一步加深 上完今天的课后,我才知道一个接口可以有多个实现类,一个实现类可以同时接多个接口. 现在就用代码来解释吧!!! 举例用人 ...
- headfirst设计模式(5)—工厂模式体系分析及抽象工厂模式
先编一个这么久不写的理由 上周我终于鼓起勇气翻开了headfirst设计模式这本书,看看自己下一个设计模式要写个啥,然后,我终于知道我为啥这么久都没写设计模式了,headfirst的这个抽象工厂模式, ...
- 2018/1.6 Javascript 继承和克隆
这种写法不是对象克隆,就是把obj的内存地址赋给obj2 通过 for in 克隆 不管公有还是私有的都克隆成私有的. js提供了一个克隆方法 objct.create() var obj2=obje ...
- 如何在sublime text3运行nodejs
步骤一:nodejs的安装1到nodejs的官网下载安装包,直接点击Install即可.(参照自己的系统版本安装,官网会自动匹配系统的版本.) 2双击安装包,进行安装 3务必注意的地方:安装路径,要记 ...
- 程序员50题(JS版本)(七)
程序31:有一个已经排好序的数组.现输入一个数,要求按原来的规律将它插入数组中 var test=[213,134,134,84,62,11]; const num=33; test.push(num ...
- 常见的网页图像格式有 ico、jpg、png、gif,说说他们各自的应用场景
1.ico:一般作为网页的标题上面的图标出现,文件 favicon.ico一般存放在网站根目录 2.jpg:非常适合作为储存像素色彩丰富的图片.例如照片等等 3.png:分为 png-8 以及 png ...
- 基于python的种子搜索网站,你懂得!
该项目是基于python的web类库django开发的一套web网站,给师弟做的毕业设计.本人的研究方向是一项关于搜索的研究项目.在该项目中,笔者开发了一个简单版的搜索网站,实现了对数据库数据的检索和 ...
- MySQL, XE7使用FireDAC连接MySQL数据库
发现使用DBExpress进行MySQL连接老是有莫名其妙的问题,直接改为FireDAC 在上一篇的DataSnap服务框架程序中,将连接的数据库由MSSQL改为本文的MySQL 使用的MySQL数据 ...
- Spark MLlib FPGrowth关联规则算法
一.简介 FPGrowth算法是关联分析算法,它采取如下分治策略:将提供频繁项集的数据库压缩到一棵频繁模式树(FP-tree),但仍保留项集关联信息.在算法中使用了一种称为频繁模式树(Frequent ...
- 借书证信息管理系统,C语言实现
自己实现的如有缺漏欢迎提出 /* 原创文章 转载请附上原链接: https://www.cnblogs.com/jiujue/p/10325628.html */ 设计内容: 设计一个排序和查找系 ...