Pollard-Rho算法:在期望 O ( n 1 4 ) \mathcal{O}(n^\frac{1}{4}) O(n41)的时间复杂度内分解一个较大的数N的质因数
1.用Miller-Rabin判断该数是否为质数,是则返回;
2.用生日悖论搜索该数的某个因数;
3.对于得到的因子继续调用Pollard-Rho分解其因数.
优化:
在分解质因数时gcd所用次数太多,因为gcd是积性函数,可以将多次所得结果乘起来再一起算gcd。
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define RG register
#define ll long long
using namespace std;
ll n,Ans=0;
ll read()
{
ll res=0;char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
return res;
}
ll print(ll x) {
if(x>9)print(x/10);
putchar(x%10+48);
}
ll max(ll a,ll b) { return a>b?a:b; }
ll qm(ll x,ll y,ll p) {
return (x*y-(ll)((long double)x/p*y)*p+p)%p;
}
ll pw(int a,ll b,ll p)
{
RG ll ans=1;a%=p;
for(;b;b>>=1) {
if(b&1) ans=qm(ans,a,p);
a=qm(a,a,p);
}
return ans;
}
bool MR(int x,ll p)//Miller-Rabin
{
if(pw(x,p-1,p)!=1) return false;
RG int k=p-1;
while(k%2==0)
{
k>>=1;
int t=pw(x,k,p);
if(t!=1&&t!=p-1) return false;
if(t==p-1) return true;
}
return true;
}
bool check(ll p)
{
if(p==46856248255981||p<2) return false;
if(p==2||p==3||p==5||p==61||p==24251) return true;
return MR(2,p)&&MR(3,p)&&MR(5,p)&&MR(61,p)&&MR(24251,p);
}
ll gcd(ll a,ll b) { return !b ? a : gcd(b,a%b) ; }
void Pollard_Rho(ll x)
{
if(x==1) return;
if(x%2==0) {
Ans=max(Ans,2),Pollard_Rho(x/2);
return;
}
if(x%3==0) {
Ans=max(Ans,3),Pollard_Rho(x/3);
return;
}
if(x%5==0) {
Ans=max(Ans,5),Pollard_Rho(x/5);
return;
}
if(check(x)) return Ans=max(Ans,x),void();
RG ll a=7,c=rand(),k=1,s=1;
RG ll b=(qm(a,a,x)+c)%x;
RG int p=1;
while(b!=a&&k==1)
{
a=(qm(a,a,x)+c)%x;
b=(qm(b,b,x)+c)%x,b=(qm(b,b,x)+c)%x;
++p;
if(a!=b) s=qm(s,(b-a),x);
if(p==127||a==b) k=gcd(x,abs(s)),p=0,s=1;
}
Pollard_Rho(k),Pollard_Rho(x/k);
}
int main()
{
srand(19260817);
RG int T=read();
while(T--)
{
n=read(),Ans=0;
Pollard_Rho(n);
if(Ans==n) printf("Prime");
else print(Ans); putchar(10);
}
return 0;
}