首页 > 编程语言 >Pollard-Rho 算法

Pollard-Rho 算法

时间:2023-10-11 16:03:35浏览次数:38  
标签:return cur int ll Pollard 算法 Rho inline equiv

Miller-Rabin 素性检测

部分内容摘自 题解 P4718/论 Miller-Rabin 算法的确定性化 - It's LUNATIC time!)

根据费马小定理,若 \(p\) 为素数,那么对于 \(1 \leq a < p\),都有 \(a^{p-1} \equiv 1 \pmod p\)。

因此,若存在 \(1 \leq a < p\) 使得 \(a^{p-1} \not\equiv 1 \pmod p\),那么 \(p\) 一定不是素数。

于是有费马素性检测:在 \([1,p)\) 中随机选取几个 \(a\),然后使用快速幂来检测是否有 \(a^{p-1} \equiv 1 \pmod p\)。如果对于每个选取的 \(a\),\(p\) 都通过了检测,那么费马素性检测认为 \(p\) 是素数。

但是有的合数 \(p\) 满足对于 \(1 \leq a < p\),都有 \(a^{p-1} \equiv 1 \pmod p\)。这些数被称为卡迈克尔数。因此,我们需要检测 \(p\) 的更多性质。

二次探测定理:若 \(p\) 为奇素数,则 \(x^2 \equiv 1 \pmod p\) 的解为 \(x \equiv \pm 1 \pmod p\)。

若 \(p\) 为奇数,显然 \(p-1\) 是偶数。首先令 \(d = p-1\),然后判断 \(a^d \bmod p\) 是否为 \(1\),若不是则 \(p\) 为合数。接下来,若 \(d\) 为偶数则令 \(d\) 除以 \(2\),然后重复上述判断,直到 \(d\) 为奇数或 \(a^d \not\equiv 1 \pmod p\)。

如果最后一步中 \(a^d \not \equiv \pm 1 \pmod p\),则 \(p\) 一定为合数,否则 Miller-Rabin 素性检测认为它是素数。

事实上只需要选择前 \(12\) 个素数为底数就可以适用于 \(2^{78}\) 内的素性检测。

struct MillerRabin{
	int prime[20]={2,3,5,7,11,13,17,19,23,29,31,37};
	inline bool test(int v,ll p){
		ll d=p-1,cur=qpow(v,d,p);
		if(cur!=1) return false;
		while(!(d&1)){
			d>>=1,cur=qpow(v,d,p);
			if(cur==p-1) return true;
			else if(cur!=1) return false;
		}
		return true;
	}
	inline bool check(ll x){
		if(x<=40){
			for(int i=0;i<12;++i) if(x==prime[i]) return true;
			return false;
		}
		for(int i=0;i<12;++i) if(!test(prime[i],x)) return false;
		return true;
	}
}T;

Pollard-Rho 算法

Pollard-Rho 算法用于在 \(O(n^{1/4})\) 的复杂度计算合数 \(n\) 的某个非平凡因子。

考虑一个随机函数 \(f(x) = (x^2+c) \bmod n\),那么取 \(f\) 的很多项相邻作差求绝对值,很大概率能够取到一个数和 \(n\) 的 GCD 不是 \(1\)。

我们倍增一下。每次取 \([2^k,2^{k+1})\) 这一段,设段头的 \(f(x)\) 值为 \(s\),这一段里面其它的值为很多个 \(t\),那么每次把 \(|s - t|\) 乘起来对 \(t\) 取模,如果乘了 \(127\) 次就取一下模,然后求一遍 GCD。

反正这是玄学,它能找就当它能找吧。

# include <bits/stdc++.h>
// # define int long long
const int N=100010,INF=0x3f3f3f3f;

typedef __int128 ll;

std::mt19937 rng(time(0));

inline ll qpow(ll d,ll p,ll MOD){
	ll ans=1;
	while(p){
		if(p&1) ans=ans*d%MOD;
		d=d*d%MOD,p>>=1;
	}
	return ans;
}

struct MillerRabin{
	int prime[20]={2,3,5,7,11,13,17,19,23,29,31,37};
	inline bool test(int v,ll p){
		ll d=p-1,cur=qpow(v,d,p);
		if(cur!=1) return false;
		while(!(d&1)){
			d>>=1,cur=qpow(v,d,p);
			if(cur==p-1) return true;
			else if(cur!=1) return false;
		}
		return true;
	}
	inline bool check(ll x){
		if(x<=40){
			for(int i=0;i<12;++i) if(x==prime[i]) return true;
			return false;
		}
		for(int i=0;i<12;++i) if(!test(prime[i],x)) return false;
		return true;
	}
}T;
ll res;

inline ll read(void){
	ll res,f=1;
	char c;
	while((c=getchar())<'0'||c>'9')
		if(c=='-') f=-1;
	res=c-48;
	while((c=getchar())>='0'&&c<='9')
		res=res*10+c-48;
	return res*f;
}

inline ll f(ll x,ll c,ll n){
	return (x*x+c)%n;
}
inline ll myabs(ll x){
	return (x>0)?x:-x;
}
inline ll gcd(ll a,ll b){
	return (!b)?a:gcd(b,a%b);
}
inline ll PollardRho(ll x){ // 有的时候会有 s = t,此时成环了,不需要继续找下去
	ll s=0,t=0,val=1,c=rng()%(x-1)+1,d;
	for(int ga=1;;ga<<=1,s=t,val=1){
		for(int cur=1;cur<=ga;++cur){
			t=f(t,c,x),val=myabs(s-t)*val%x;
			if(cur==127){ 
				d=gcd(val,x);
				if(d>1) return d;
			}
		}
		d=gcd(val,x);
		if(d>1) return d;
	}
	assert(false);
	return 114514;
}
inline void print(ll x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) print(x/10);
	putchar(x%10+'0');
	return;
}

inline void solve(ll x){
	if(x==1) return;
	if(T.check(x)){
		res=std::max(res,x);
		return;
	}
	ll cur=x;
	while(cur>=x) cur=PollardRho(x);
	while(x%cur==0) x/=cur;
	solve(cur),solve(x);
	return;
}


signed main(void){
	int T=read();
	while(T--){
		ll n=read();
		res=0,solve(n);
		if(res==n) puts("Prime");
		else print(res),puts("");
	}
	return 0;
}

标签:return,cur,int,ll,Pollard,算法,Rho,inline,equiv
From: https://www.cnblogs.com/Meatherm/p/17757380.html

相关文章

  • 关于算法竞赛中标识符命名的几点建议
    头图 引言标识符命名,一个OIer每天都在做,却基本从未在意过的操作。好的命名,既可以提高自己的调试效率,也可以提高代码可读性。方便自己,也方便别人。如果你觉得自己的代码不是很美观,又觉得码风已经定型,不如继续往下看,说不定可以让你的码风更进一步。欢迎@你身边有需要的......
  • C++ - STL算法
    5STL-常用算法 概述:算法主要是由头文件<algorithm><functional><numeric>组成。 <algorithm>是所有STL头文件中最大的一个,范围涉及到比较、交换、查找、遍历操作、复制、修改等等<numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数<funct......
  • Lnton羚通视频分析算法平台保障工人安全智慧工地安全帽解决方案
    Lnton羚通的算法算力云平台是一款出色的解决方案,具备突出的特点。该平台提供高性能、高可靠性、高可扩展性和低成本的功能,使用户能够高效地执行各种复杂的计算任务。此外,平台还提供了丰富的算法库和工具,支持用户上传和部署自定义算法,提高了平台的灵活性和个性化能力。在工地现场,由......
  • 浅谈视频智能分析预警 事件识别算法硬件智能分析网关V2版的功能 及其智能分析网关V1版
    智能分析网关V1版本和智能分析网关V2版本相比,不仅在硬件外观上有所改变,而且在算法类别上也增加了一些新的内容。因此,今天我们将重点介绍智能分析网关V2版本的相关特性。智能分析网关V2是一种先进的数据处理设备,它融合了云计算、物联网和人工智能技术,主要应用于工业生产环境中......
  • 类欧几里得算法
    快速求解\[f(a,b,c,n)=\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor\]若\(\max(a,b)\gec\)\[设s_0(n)=n+1,s_1(n)=\frac{n(n+1)}{2},s_2(n)=\frac{n(n+1)(2n+1)}{6}\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor=\sum_{i=0}......
  • 10.11算法
    买卖股票的最佳时机给定一个数组prices,它的第 i个元素 prices[i]表示一支给定股票第i天的价格。你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。如果你不......
  • 每天一算法,脑子不生锈(真押韵)
    前言看算法确实会让编码思路有所不同,看完好的方案,就会觉得自己的很low。今年开始尽量每天一道算法题,卷死自己,长期更新Question给定一个只包括'(',')','{','}','[',']'的字符串s,判断字符串是否有效。有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合......
  • 并查集的实现【学习算法】
    并查集的实现【学习算法】前言版权推荐并查集的实现最后前言2023-9-2614:38:02以下内容源自《【学习算法】》仅供学习交流使用版权禁止其他平台发布时删除以下此话本文首次发布于CSDN平台作者是CSDN@日星月云博客主页是禁止其他平台发布时删除以上此话推荐算法讲解056【必备】并......
  • 谈谈"求线段交点"的几种算法(js实现,完整版)
    谈谈"求线段交点"的几种算法(js实现,完整版)"求线段交点"是一种非常基础的几何计算,在很多游戏中都会被使用到. 下面我就现学现卖的把最近才学会的一些"求线段交点"的算法说一说,希望对大家有所帮助. 本文讲的内容都很初级,主要是面向和我一样的初学者,所以请各位算法帝......
  • Java算法之动态规划详解
    ①动态规划动态规划(DynamicProgramming,DP)是运筹学的一个分支,是求解决策过程最优化的过程。20世纪50年代初,美国数学家贝尔曼(R.Bellman)等人在研究多阶段决策过程的优化问题时,提出了著名的最优化原理,从而创立了动态规划。动态规划的应用极其广泛,包括工程技术、经济、工业生产、军事......