【洛谷P4718】【模板】Pollard-Rho算法
题目
题目链接:https://www.luogu.com.cn/problem/P4718
Miller Rabin 算法是一种高效的质数判断方法。虽然是一种不确定的质数判断法,但是在选择多种底数的情况下,正确率是可以接受的。
Pollard Rho是一个非常玄学的方式,用于在\(O(n^{1/4})\)的期望时间复杂度内计算合数n的某个非平凡因子。事实上算法导论给出的是\(O(\sqrt p)\),\(p\)是\(n\)的某个最小因子,满足\(p\)与\(n/p\)互质。但是这些都是期望,未必符合实际。但事实上Pollard Rho算法在实际环境中运行的相当不错。
这里我们要写一个程序,对于每个数字检验是否是质数,是质数就输出Prime
;如果不是质数,输出它最大的质因子是哪个。
\(T\leq 350,n\leq 10^{18}\)。
思路
嗯好。
反正玄学就完事了。
注意光速乘的时候不要 (res%MOD+MOD)%MOD
,常数巨大。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
const int prm[10]={0,2,3,5,7,11,13,17,19,23};
int Q;
ll n,maxd;
ll fmul(ll x,ll y,ll MOD)
{
ll z=(ld)x*y/MOD,res=x*y-z*MOD;
if (res<0) return res+MOD;
if (res>=MOD) return res-MOD;
return res;
}
ll fpow(ll x,ll k,ll MOD)
{
ll ans=1;
for (;k;k>>=1,x=fmul(x,x,MOD))
if (k&1) ans=fmul(ans,x,MOD);
return ans;
}
ll gcd(ll x,ll y)
{
return y?gcd(y,x%y):x;
}
bool MR(ll n)
{
for (int i=1;i<=9;i++)
{
if (n==prm[i]) return 1;
if (n<prm[i]) return 0;
ll m=n-1,power=fpow(prm[i],m,n);
while (power==1 && !(m&1))
m>>=1,power=fpow(prm[i],m,n);
if (power!=1 && power!=n-1) return 0;
}
return 1;
}
ll work(ll n)
{
ll val=1,s=0,t=0,c=rand()%(n-1);
for (int lim=1,i=1;;i++)
{
t=(fmul(t,t,n)+c)%n;
val=fmul(val,abs(t-s),n);
if (i==lim || i%127==0)
{
ll d=gcd(val,n);
if (d>1) return d;
if (i==lim) s=t,val=1,lim<<=1;
}
}
}
void PR(ll n)
{
if (n<=maxd || n<2) return;
if (MR(n)) { maxd=n; return; }
ll d=work(n);
while (d>=n) d=work(n);
while (n%d==0) n/=d;
PR(n); PR(d);
}
int main()
{
scanf("%d",&Q);
while (Q--)
{
scanf("%lld",&n);
srand(13331U*(Q+2333)*n);
maxd=0; PR(n);
if (maxd==n) printf("Prime\n");
else printf("%lld\n",maxd);
}
return 0;
}