质因数分解
给一个数n,对他进行质因数分解
代码
for(int i = 2; i <= n; i ++)
if(n % i == 0){
cout << i << endl;
while(n % i == 0) n /= i;
}
证明以上循环可以输出n的所有质因数
- 当n为质数时,只输出n,得证。
- 当n不是质数时。
对于2,用数学归纳法证明(注意i是全程自增的)
设\(n\)的初始值为\(n_0\),\(t_i\)为可以整除\(n_i\)的第一个数
\(1)\) 由于\(t_0\)为能够整除\(n_0\)的第一个数,可知\(n_0\)不存在\(2 ,...,t_0 - 1\)的约数,
又因为\(n_0 \% t_0 = 0\),所以\(t_0\)也不存在\(2 ,...,t_0 - 1\)的约数,所以\(t_0\)必为质数。
根据循环要求,将\(n_0\)中的\(t_0\)除完变为\(n_1\),\(n\)的值变为\(n_1\)。
\(2)\) 假设\(t_k(k\ge 1)\)为素数,所以\(t_k\)不存在\(2,...,t_k - 1\)的约数,由于\(n_k \% t_k = 0\), 所以\(n_k\)也不存在\(2,...,t_k - 1\)的约数,所以将\(n_k\)中的\(t_k\)全部除完得到的\(n_{k + 1}\)不存在\(2,...,t_k\)的约数,又因为\(t_{k + 1}\)为第一个能够整除\(n_{k + 1}\)的数,所以\(t_k + 1, ...,t_{k+1} -1\)中不存在\(n_{k+1}\)的约数,所以\(2,...,t_{k+1} - 1\)中不存在\(n_{k+1}\)的约数,又因为\(n\%t_{k+1}=0\),所以\(t_{k+1}\)没有\(2,...,t_{k+1} - 1\)中的约数,所以\(t_{k+1}\)为素数。
\(3)\) 获证当n不是素数时,在此循环中所有可以整除n的i均为素数。
由1和2,所以此循环可以输出n的所有质因子。
优化
原始代码复杂度为\(O(n)\)。
首先证明一个结论:对于一个数n,最多含有一个(数量上,不是种类上)大于sqrt(n)的质因子。
证明:因为对于一个数n可对其质因数分解为\(n = p_{1}^{k1}p_{2}^{k2}...p_{t}^{kt}\),显然不可以存在两个及以上的大于sqrt(n)的质因子,如果存在两个及以上的大于sqrt(n)的质因子,必有\(n <p_{1}^{k1}p_{2}^{k2}...p_{t}^{kt}\)。
所以质因子的枚举范围可以缩小为\(2,...,[\sqrt n]\),最后需要特判一下n是否为1,若不为1,就要把n也输出。
复杂度:最好情况下\(n = 2^k\), 此时复杂度为\(O(logn)\),最坏情况下\(O(\sqrt n)\)
#include<iostream>
using namespace std;
int n;
void divide(int a){
for(int i = 2; i <= a / i; i ++){
if(a % i == 0){
int s = 0;
while(a % i == 0){
a /= i;
s ++;
}
cout << i << ' ' << s << endl;
}
}
if(a > 1) cout << a << ' ' << 1 << endl;
}
int main(){
cin >> n;
while(n --){
int a;
cin >> a;
divide(a);
puts("");
}
return 0;
}