Description
给出一个数N,求N其中的一个因数。(1和N外)
N<=10^18
好玄学的一个东西。
首先,如果直接暴力,根号n肯定过不了。
在讲正解之前,我们先来讲讲道理。
生日悖论
在n个人中,生日(月份和日期)两两不同的概率是多少。
一年取365天
很显然,第1个人的生日可以取
365365
第2个人为
364365
以此类推。
总概率为
∏i=0n−1365−i365
代入n,发现当n=23的时候,概率就已经小于50%了。
也就是说,普通的一个班里面有至少50%的概率有两个人的生日在同一天。
是不是很玄学?233
所以才叫悖论嘛~
Pollard’s Rho 算法
知道这个东西有什么卵用吗?
我们先稍稍修改一下这个问题,
从[1~1000]中选出两个数i,j,|i-j|=l的概率是多少。
大约为
1500
那么如果我们选择k个数,x1~xk,使得其中有两个数的差为l的概率呢?
写个暴力计算下
当k=30时,概率就超过了50%
k=100时,基本已经100%了!
那么我们可以运用这个结论,每次rand()多一个数,判断一下,是否有差值是N的因数。
效率大大滴提高了!
从某一篇文章上看到,大约是
O(N14)
玄学♂
不过,rand可能出现神奇的东西。手打一个
f(x)=x*x+a %N
但是,在有些数据下,它会死循环。
那么我们只需要找出环,重新rand出a,再做一次。
判环可以用Floyd的聪明又有趣的方法。
A和B在同一个环上跑,怎么知道A已经跑了一圈?
我们让B的速度是A的2倍,那么当B追上A的时候A已经跑了一圈了~
玄学♀
Code
ll f(ll x) {return (mult(x,x)+t)%N;}
for(;!q;t=rand()%100) {
a=t;b=f(t);
while (a!=b) {
a=f(a);b=f(f(b));
ll k=gcd(abs(a-b),N);
if (k>1) {
q=k;p=N/k;break;
}
}
}