[luogu4718]Pollard-Rho算法
模板题
题解主要分为两部分,即Miller-Robin判素数以及关于Pollard-Rho算法
1.Miller-Robin判素数
对于一个数$n$,判定其是否为素数,依次执行以下几步——
(1)若$n=2$在$n$为素数,否则若$n=1$或$n\equiv 0(mod\ 2)$则$n$非素数
(2)对于一个素数$p$,分类讨论
若$(p,n)\ne 1$($=p$),显然根据$p$是否等于$n$可以直接确定$n$是否为素数
若$(p,n)=1$,根据费马小定理要求$p^{n-1}\equiv 1(mod\ n)$
同时若$n$为素数,$x^{2}\equiv 1(mod\ n)$的解仅有$x\equiv 1或n-1(mod\ n)$(将其分解即可)
假设$n-1=2^{k}m$,则$\forall 1\le i\le k$且$p^{2^{i}m}\equiv 1(mod\ n)$,满足$p^{2^{i-1}m}\equiv 1或n-1(mod\ n)$
(3)重复第2个步骤若干次(当然可以预先选好素数)
2.Pollard-Rho算法
基本思路
考虑对$n$进行质因数分解,先使用Miller-Robin在$o(\log n)$的时间内判定$n$是否是素数,若$n$为素数即结束,否则需要快速找到一个$1\le x<n$且$\gcd(n,x)>1$,之后递归分解$\gcd(x,n)$和$\frac{n}{\gcd(n,x)}$即可
构造方式
关于如何找到$x$,我们考虑如下的方式:
构造一个序列$a_{i}$,其中$a_{i}=a_{i-1}^{2}+c(i\ge 2)$,$a_{1}$和$c$均为随机
(关于这个递推式并没有太大的实际意义,只是$a_{i}$由$a_{i-1}$唯一确定且分布较为随机)
从小到大枚举$i\ge 1$,并令$x\equiv a_{i}-a_{2i}(mod\ n)$(要求$0\le x<n$),若$x=0$则重新随机$a_{1}$和$c$并再次执行,否则判定$x$是否满足条件($\gcd(n,x)>1$),若满足条件即可递归
复杂度分析
下面,我们来考虑找到$x$的期望$i$大小或无法找到的概率——
先考虑另外一个问题,对于一个$n$,第一次出现$a_{i}\equiv a_{2i}(mod\ n)$的位置
令$x$为最小的整数,满足$\exists 1\le y<x$且$a_{x}\equiv a_{y}(mod\ n)$,显然$y$是唯一的,再取这个唯一的$y$
考虑序列$\{a_{i}\ mod\ n\}$,根据$a_{i}$由$a_{i-1}$唯一确定(在模意义下显然也满足),$x$和$y$实际上分别是第2次和第1次进入循环的位置,更具体的有$\forall i\ge y,a_{i}\equiv a_{i+(x-y)}(mod\ n)$
在$[y,x)$中取$k\equiv 0(mod\ x-y)$(显然唯一),根据循环的性质不难得到$a_{k}\equiv a_{2k}(mod\ n)$,且由于$x$和$y$最小的性质,还可以证明$k$也是最小的,即$k$就是这个位置
再考虑$k$的期望,由于$k<x$也可以看作$x$的期望,由于序列$a_{i}$分布可以认为是随机的,根据$x$的定义可以发现$x$的期望即在$[0,n)$范围内随机若干次出现重复数字的期望次数
根据生日悖论,其期望是$o(\sqrt{n})$的,具体推导如下——
考虑$P(x\le X)$(即$x\le X$的概率),等价于$X$个数中存在相同,不难得到$P(X)=1-\prod_{i=0}^{X-1}(1-\frac{i}{n})$
根据均值不等式,有$\sqrt[X]{\prod_{i=0}^{X-1}(1-\frac{i}{n})}\le {\frac{1}{X}\sum_{i=0}^{X-1}(1-\frac{i}{n})}=\frac{2n-X+1}{n}$
代入后,即$P(X)\ge 1-(\frac{2n-X+1}{2n})^{X}=1-(1-\frac{X}{2n})^{X}$
由于$\frac{1}{1-x}=\sum_{i=0}^{\infty}x^{i}$,而根据泰勒展开有$e^{x}=\sum_{i=0}^{\infty}\frac{1}{i!}x^{i}<\frac{1}{1-x}$,即$1-x<e^{-x}$
将之代入,即$P(X)\ge 1-e^{-\frac{X^{2}}{2n}}\ge \frac{1}{2}$,即$e^{-\frac{X^{2}}{2n}}\le \frac{1}{2}$,$X\ge \sqrt{-2n\ln\frac{1}{2}}\sim o(\sqrt{n})$
(真的求期望$E(x)$也就要对$\sum_{i=0}^{n-1}(e^{-\frac{1}{2n}})^{i^{2}}$求值,可能比较困难)
考虑完这个问题后,回归原问题,令$p$为$n$的最小素因子(显然$p\le \sqrt{n}$),那么$gcd(n,x)>1$的充分条件是$p|x$,而$p|x$(且$x\ne 0$)这个条件还可以被表述为:$a_{i}\not\equiv a_{2i}(mod\ n)$且$a_{i}\equiv a_{2i}(mod\ p)$
根据前面的结论,$a_{i}\equiv a_{2i}(mod\ p)$的期望位置是$o(\sqrt{p})$的
但还有一个问题,即有可能同时还满足$a_{i}\equiv a_{2i}(mod\ n)$,此时$x=0$,即无法找到
但由于前者期望位置是$o(\sqrt{n})$的,后者是$o(\sqrt{p})$的,两者并不同阶,因此这个概率并不大,可以认为在$o(1)$次内一定可以找到(这里应该是极其口胡的,但并不知道如何更严谨的说明QAQ)
每一次查找(包括失败)复杂度都是期望$o(\sqrt{p})$,查找次数又是$o(1)$,再算上$\gcd$的复杂度,因此单次分解复杂度即为$o(\sqrt{p}\log n)$
虽然至多有$o(\log n)$次递归,而$p$又是$o(\sqrt{n})$的,总复杂度即$o(n^{\frac{1}{4}}\log^{2}n)$,但事实上这个复杂度还可以进一步的精确——
(以下过程通俗的来说,即若递归次数过多则$p$一定很小,当$p$是$o(\sqrt{n})$这个级别时递归次数是$o(1)$的,因此复杂度是$o(n^{\frac{1}{4}}\log n)$的)
考虑递归后分别是$d$和$\frac{n}{d}$,其中较小的不超过$\sqrt{n}$,其复杂度根据前面是$o(n^{\frac{1}{8}}\log^{2}n)$,可以忽略,换言之递归时我们仅关心于大于$\sqrt{n}$的部分的复杂度
不妨假设$d>\sqrt{n}$,那么$n$的最小素因子不超过$\frac{n}{d}$,即$T(n)=\max_{d|n}T(d)+\sqrt{\frac{n}{d}}\log n$
对于其中$\frac{n}{d}\le n^{\frac{1}{4}}$(前面的$n$指该次递归,后者的$n$指全局),即使有$\log$次复杂度也仅为$o(n^{\frac{1}{8}}\log^{2}n)$,同样可以忽略,而若$\frac{n}{d}>n^{\frac{1}{4}}$,那么即至多4次,总复杂度为$o(n^{\frac{1}{4}}\log n)$
综上,即说明了复杂度为$o(n^{\frac{1}{4}}\log n)$
关于gcd的优化
可以将若干次gcd组合在一起计算,即若求$\gcd(x,n)$和$\gcd(y,n)$,不妨直接求$\gcd(xy\ mod\ n,n)$
但这样就不能每一次都判定,可以考虑隔一段时间判定一次,关于这个间隔比较随意,只需在$[\log n,n^{\frac{1}{4}}]$中,即可令复杂度降为$o(n^{\frac{1}{4}})$,另外在$x=0$时还需要将之前的再求一次
(另外可能会涉及模$n$意义下两数乘法,需要使用int128或其他技巧)

1 #include<bits/stdc++.h>
2 using namespace std;
3 #define ll long long
4 int t,p[5]={3,5,7,11,13};
5 ll n;
6 ll mul(ll x,ll y,ll n){
7 return (__int128)x*y%n;
8 }
9 ll gcd(ll x,ll y){
10 if (!y)return x;
11 return gcd(y,x%y);
12 }
13 ll pow(ll n,ll m,ll mod){
14 ll s=n,ans=1;
15 while (m){
16 if (m&1)ans=mul(ans,s,mod);
17 s=mul(s,s,mod);
18 m>>=1;
19 }
20 return ans;
21 }
22 bool check(ll n){
23 if (n==2)return 1;
24 if (n%2==0)return 0;
25 ll m=n-1,k=0;
26 while (m%2==0){
27 k++;
28 m/=2;
29 }
30 for(int i=0;i<5;i++){
31 if (n%p[i]==0)return n==p[i];
32 ll s=pow(p[i],m,n);
33 for(int j=0;j<k;j++){
34 if ((mul(s,s,n)==1)&&(s!=1)&&(s!=n-1))return 0;
35 s=mul(s,s,n);
36 }
37 if (s>1)return 0;
38 }
39 return 1;
40 }
41 ll get_fac(ll n){
42 ll x=rand()%n,c=rand()%n,y=(mul(x,x,n)+c)%n,z=1,tot=0;
43 while (1){
44 if ((x==y)||(tot%100==0)){
45 if (gcd(z,n)>1)return gcd(z,n);
46 if (x==y)return 1;
47 z=1;
48 }
49 tot++;
50 z=mul(z,(x+n-y)%n,n);
51 if (!z)return gcd((x+n-y)%n,n);
52 x=(mul(x,x,n)+c)%n;
53 y=(mul(y,y,n)+c)%n;
54 y=(mul(y,y,n)+c)%n;
55 }
56 }
57 ll calc(ll n){
58 if (check(n))return n;
59 while (1){
60 ll p=get_fac(n);
61 if (p>1)return max(calc(p),calc(n/p));
62 }
63 }
64 int main(){
65 srand(time(0));
66 scanf("%d",&t);
67 while (t--){
68 scanf("%lld",&n);
69 ll ans=calc(n);
70 if (ans==n)printf("Prime\n");
71 else printf("%lld\n",ans);
72 }
73 }
[luogu4718]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算法
前言 \(Pollard\ Rho\)是一个著名的大数质因数分解算法,它的实现基于一个神奇的算法:\(MillerRabin\)素数测试(关于\(MillerRabin\),可以参考这篇博客:初学Mi ...
- 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和它本身以外能整除它的数).事书上给出的复杂度是 \( ...
- 浅谈 Miller-Robbin 与 Pollard Rho
前言 $Miller-Robbin$ 与 $Pollard Rho$ 虽然都是随机算法,不过用起来是真的爽. $Miller Rabin$ 算法是一种高效的质数判断方法.虽然是一种不确定的质数判断法, ...
- Pollard Rho因子分解算法
有一类问题,要求我们将一个正整数x,分解为两个非平凡因子(平凡因子为1与x)的乘积x=ab. 显然我们需要先检测x是否为素数(如果是素数将无解),可以使用Miller-Rabin算法来进行测试. Po ...
随机推荐
- SpringBoot 如何进行限流?老鸟们都这么玩的!
大家好,我是飘渺.SpringBoot老鸟系列的文章已经写了四篇,每篇的阅读反响都还不错,那今天继续给大家带来老鸟系列的第五篇,来聊聊在SpringBoot项目中如何对接口进行限流,有哪些常见的限流算 ...
- nginx配置禁止爬虫配置
1.在配置文件里添加禁止爬虫配置 server { ------ #添加如下内容即可防止爬虫 if ($http_user_agent ~* "qihoobot|Baiduspider|Go ...
- IL合集
由于之前写的表达式树合集,未编写任何注释且是以图片的形式展现给大家,在这里向各位看官道歉了,接下来为大家奉上新鲜出炉的香喷喷的IL合集,后面会持续更新,各位看官点关注不迷路,之前答应的手写IOC以及多 ...
- 【Docker】(9)---每天5分钟玩转 Docker 容器技术之镜像
镜像是 Docker 容器的基石,容器是镜像的运行实例,有了镜像才能启动容器.为什么我们要讨论镜像的内部结构? 如果只是使用镜像,当然不需要了解,直接通过 docker 命令下载和运行就可以了. 但如 ...
- java设计模式_工厂模式
关于设计模式 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结,是一种设计思维,使用设计模式的目的:为了代码可重用性.让代码更容易被他人理解.保证 ...
- 【数据结构与算法Python版学习笔记】目录索引
引言 算法分析 基本数据结构 概览 栈 stack 队列 Queue 双端队列 Deque 列表 List,链表实现 递归(Recursion) 定义及应用:分形树.谢尔宾斯基三角.汉诺塔.迷宫 优化 ...
- Beta阶段第十次会议
Beta阶段第十次会议 时间:2020.5.26 完成工作 姓名 完成工作 难度 完成度 ltx 1.修正小程序新闻bug2.修正小程序认证bug 中 80% xyq 1.上传信息编辑部分代码到服务器 ...
- Noip模拟79 2021.10.17(题目名字一样)
T1 F 缩点缩成个$DAG$,然后根据每个点的度数计算期望值 1 #include<cstdio> 2 #include<cstring> 3 #include<vec ...
- 奔跑吧linux-第三章实验
基于树莓派+openeuler平台 实验 3-2:汇编语言练习--查找最大数 1.实验目的 通过本实验了解和熟悉 ARM64 汇编语言. 2.实验要求 使用 ARM64 汇编语言来实现如下功能:在给定 ...
- Luogu P1084 疫情控制 | 二分答案 贪心
题目链接 观察题目,答案明显具有单调性. 因为如果用$x$小时能够控制疫情,那么用$(x+1)$小时也一定能控制疫情. 由此想到二分答案,将问题转换为判断用$x$小时是否能控制疫情. 对于那些在$x$ ...