// C++ Versionlist<int>breakdown(intN){list<int>result;for(inti=2;i*i<=N;i++){if(N%i==0){// 如果 i 能够整除 N,说明 i 为 N 的一个质因子。while(N%i==0)N/=i;result.push_back(i);}}if(N!=1){// 说明再经过操作之后 N 留下了一个素数result.push_back(N);}returnresult;}
1
2
3
4
5
6
7
8
9
10
11
# Python Versiondefbreakdown(N):result=[]foriinrange(2,int(sqrt(N))+1):ifN%i==0:# 如果 i 能够整除 N,说明 i 为 N 的一个质因子。whileN%i==0:N=N//iresult.append(i)ifN!=1:# 说明再经过操作之后 N 留下了一个素数result.append(N)returnresult
我们能够证明 result 中的所有元素均为 N 的素因数。
证明 result 中均为 N 的素因数
首先证明元素均为 N 的素因数:因为当且仅当 N % i == 0 满足时,result 发生变化:储存 i,说明此时 i 能整除 \frac{N}{A},说明了存在一个数 p 使得 pi=\frac{N}{A},即 piA = N(其中,A 为 N 自身发生变化后遇到 i 时所除的数。我们注意到 result 若在 push i 之前就已经有数了,为 R_1,\,R_2,\,\ldots,\,R_n,那么有 N=\frac{N}{R_1^{q_1}\cdot R_2^{q_2}\cdot \cdots \cdot R_n^{q_n}},被除的乘积即为 A)。所以 i 为 N 的因子。
其次证明 result 中均为素数。我们假设存在一个在 result 中的合数 K,并根据整数基本定理,分解为一个素数序列 K = K_1^{e_1}\cdot K_2^{e_2}\cdot\cdots\cdot K_3^{e_3},而因为 K_1 < K,所以它一定会在 K 之前被遍历到,并令 while(N % k1 == 0) N /= k1,即让 N 没有了素因子 K_1,故遍历到 K 时,N 和 K 已经没有了整除关系了。
值得指出的是,如果开始已经打了一个素数表的话,时间复杂度将从 O(\sqrt N) 下降到 O(\sqrt{\frac N {\ln N}})。去 筛法 处查阅更多打表的信息。
最大公约数一定是某个数的约数,即 \forall k \in\mathbf{N}_{+},\gcd(k,n)|n,只要选适当的 k 使得 1<\gcd(k,n)< n,就可以求得一个约数 \gcd(k,n)。满足这样条件的 k 不少,k 有若干个质因子,每个质因子及其倍数都是可行的。
将生日悖论应用到随机算法中,伪随机数序列中不同值的数量约为 O(\sqrt{n}) 个。设 m 为 n 的最小非平凡因子,显然有 m\leq \sqrt{n}。记 y_i = x_i \pmod m,推导可得:
\begin{aligned} y_{i+1}&=x_{i+1} \bmod m \\ & = (x_{i}^2+c \bmod n) \bmod m \\ & = (x_i ^ 2 + c) \bmod m \\ & = ((x_i \bmod m) ^ 2 + c) \bmod m \\ & = y_i ^ 2 + c \pmod m \end{aligned}
我们每次令 d=\gcd(|x_i-x_j|,n),判断 d 是否满足 1< d< n,若满足则可直接返回 d。由于 x_i 是一个伪随机数列,必定会形成环,在形成环时就不能再继续操作了,直接返回 n 本身,并且在后续操作里调整随机常数 c,重新分解。
基于 Floyd 判环的 Pollard-Rho 算法
1
2
3
4
5
6
7
8
9
10
11
12
13
// C++ VersionllPollard_Rho(llN){llc=rand()%(N-1)+1;llt=f(0,c,N);llr=f(f(0,c,N),c,N);while(t!=r){lld=gcd(abs(t-r),N);if(d>1)returnd;t=f(t,c,N);r=f(f(r,c,N),c,N);}returnN;}