Miller_Rabin和Pollard_rho素数模板——POJ-2429的题解

本文介绍了一种结合Miller-Rabin素性测试与Pollard's Rho因数分解算法的实现方案,用于高效地判断大整数的素性并进行因数分解。该方案适用于大整数处理,通过随机化算法提高了效率,并详细展示了如何寻找最接近平方根的因子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网络上有很多讲解,不再赘述。此处记载此题题解以供复习之用。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<set> 
#include<algorithm>
using namespace std;
typedef long long ll;
ll temp,pr[101],f[101],t,ans;
bool book[2000001];
ll random(ll n)//随机数 
{
	return ((double)rand()/RAND_MAX*n+0.5);
}
ll q_mul(ll a,ll b,ll mod)//快速乘 
{
	ll ans=0;
	while(b)
	{
		if(b&1)
			ans=(ans+a)%mod;
		b>>=1;
		a=(a+a)%mod;
	}
	return ans;
}
ll q_pow(ll a,ll b,ll mod)//快速幂 
{
	ll res=1;
	while(b)
	{
		if(b&1)
			res=q_mul(res,a,mod);
		b>>=1;
		a=q_mul(a,a,mod);
	}
	return res;
}
bool go(ll a,ll n)//Miller-rabin的核心算法 
{
	ll r=n-1,j=0;
	while(r&1==0)
	{
		r>>=1;
		j++;
	}
	ll x=q_pow(a,r,n);
	if(x==1||x==n-1)
		return true;
	while(j--)
	{
		x=q_mul(x,x,n);
		if(x==n-1)
			return true;
	}
	return false;
}
bool miller_rabin(ll n)
{
	if(n==2)
		return true;
	if(n<2||n&1==0)
		return false;
	for(int i=1;i<=20;i++)
	{
		ll a=random(n-2)+1;
		if(!go(a,n))
			return false;
	}
	return true;
}
ll gcd(ll a,ll b)
{
	return b==0?a:gcd(b,a%b);
}
ll pollard_rho(ll p,ll c)
{
	ll i=1,k=2,x=random(p-1)+1,y,d;
	y=x;
	while(1)
	{
		i++;
		x=(q_mul(x,x,p)+c)%p;
		d=gcd(y-x,p);
		if(d>1&&d<p)//找到 
			return d;
		if(y==x)//循环了没找到 
			return p;
		if(i==k)//优化功能 
			y=x,k<<=1;
	}
}
void insert(ll n)//pr数组记录约数值,f数组记录个数 
{
	int i;
	for(i=0;i<t;i++)
		if(pr[i]==n)
			break;
	if(i<t)
		f[i]++;
	else
		pr[t]=n,f[t++]=1;	
}
void find(ll n,ll c)//将辨别素数和查找合数约数的两个算法放在一个函数里了 
{
	if(n==1)
		return;
	//这里大的数字用Miller-rabin查的,小的素数用筛子 
	if(n>=2000000)
	{
		if(miller_rabin(n))
		{
			insert(n);
			return;
		}
	}
	else
	{
		if(!book[n])
		{
			insert(n);
			return;
		}
	}	
	
	ll p=n;
	while(p>=n)//直到随机到他的因数 
		p=pollard_rho(p,c--);
	find(p,c);
	find(n/p,c);	
}
void search(ll i,ll x,ll q)//查找最接近sqrt的那个 
{
	if(i==t)return;
	if(x>ans&&x<=q) ans=x;
	search(i+1,x,q);
	x*=f[i];
	if(x>ans&&x<=q) ans=x;
	search(i+1,x,q);
}
int main()
{
	ll a,b,n,m;
	
	book[0]=book[1]=true;//筛小素数 
	for(int i=2;i*i<=2000000;i++)
	{
		if(!book[i])
			for(int j=2*i;j<=2000000;j+=i)
				book[j]=true;
	}
	
	while(~scanf("%lld%lld",&n,&m))
	{
		t=0;
		ll multiple=m/n;
		find(multiple,21373425);//常数c是随意定的 
		temp=floor(sqrt(multiple)+0.5);
		for(int i=0;i<t;i++)
		{
			ll k=1;
			for(int j=1;j<=f[i];j++)
				k*=pr[i];
			f[i]=k;//把同样的质数乘成一个整体以保证因数互质,且保存 
		}
		ans=1;
		search(0,ans,temp);//查找最接近sqrt的那个数 
		b=n*multiple/ans,a=n*ans;
		printf("%lld %lld\n",a,b);
	}
	return 0; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值