Miller-Rabin&Pollard-Rho
Miller-Rabin
二次探测定理
\(x^2 \equiv 1 \pmod{p}\Leftrightarrow x \equiv 1 \pmod{p} ~\text{or}~x \equiv -1 \pmod{p}\)
证明我不会
步骤
首先用费马小定理去除一般合数
然后对\(p^{x-1}\equiv 1\pmod x\)
若\(x-1\)为偶数
检验\(p^{\frac{x-1}{2}}\pmod x\):
- \(\ne 1,\ne x-1\) 为合数退出
- \(= 1\)继续
- \(= x-1\)认为是素数
inline char Check(re ll x,re ll p){
if(qpow(p%x,x-1,x)^1)return 0;
re ll k=x-1,t;
while(!(k&1)){
if((t=qpow(p%x,k>>=1,x))^1&&t^(x-1))return 0;
if(!(t^(x-1)))return 1;
}
return 1;
}
inline char Miller_Rabin(re ll x){
re ll i;
if(x==1)return 0;
for(i=1;i<=*pri;++i){if(!(x^pri[i]))return 1;if(!(x%pri[i])||!Check(x,pri[i]))return 0;}
return 1;
}
Pollard-Rho
思想
随机抽样一些数,其中有两者之差与待测数不互质概率会随抽样个数增大飞快增大
不靠谱的说法,期望抽样次数为\(O(\sqrt[4]n)\)
流程
首先我们需要一个伪随机数列来生成样本常用\(f(x)=(x^2+c)\mod N\)(曼德勃罗集)
为什么不选取随机数列(我指系统的),因为随机数列循环节太长
而这个伪随机数列始终会进入一个循环恰似\(\rho\)
然后考虑每次都求\(\gcd\)反而让时间退化
考虑倍增,把一段里的积累计起来(反正你又不需要知道是那个差不互质)
现在我们要走\(2^k\)步
那么每到\(127\)步或整个倍增段走完时判定一下累乘的积是否与\(x\)不互质即可
至于为什么是\(127\)……
inline ll Pollard_rho(re ll x,re ll c){
re ll goal,i,st=0,now=0,pro=1ll,d;if(c<=0)c=1ll*rand()%(x-1)+1;
for(goal=1;;goal<<=1,st=now,pro=1ll){
for(i=1;i<=goal;++i){
now=(qmul(now,now,x)+c)%x;pro=qmul(pro,Abs(now-st),x);
if(!(i%127)){d=qgcd(pro,x);if(d^1)return d;}
}
d=qgcd(pro,x);if(d^1)return d;
}
}
inline void Findfac(re ll n,re int k){
if(!(n^1)||n<=ans)return ;if(Miller_Rabin(n))return void(ans=max(ans,n));
re ll p=n;while((p=Pollard_rho(n,k--))==n);while(!(n%p))n/=p;Findfac(n,k),Findfac(p,k);
}
卡常
可以写一个很牛逼的二进制\(gcd\)
不知道哪里抄来的
#define mytz __builtin_ctzll
inline ll qgcd(ll a, ll b){
if(!a) return b;
if(!b) return a;
register int t = mytz(a|b) ;
a >>= mytz(a) ;
do{
b >>= mytz(b) ;
if(a>b){ll t=b;b=a,a=t;}
b-=a;
}while(b);
return a<<t;
}