求一个数的所有约数,枚举 [1,n][1,\sqrt n][1,n] 的所有整数,能整除 n
的就是约数,另一半约数就是 n / i
.
vector get_divisors(int n) {vector res;for (int i = 1; i <= n / i; ++i) {if (n % i == 0) {res.push_back(i);if (i != n / i) res.push_back(n / i);}}return res;
}
求约数个数基于约数个数定理:
对于一个大于 111 的正整数 nnn 可以分解质因数:
n=∏i=1kpiai=p1a1⋅p2a2⋅⋯⋅pkakn=\prod_{i=1}^kp_i^{a_i}=p_1^{a_1}\cdot p_2^{a_2}\cdot\cdots\cdot p_k^{a_k} n=i=1∏kpiai=p1a1⋅p2a2⋅⋯⋅pkak
则 nnn 的正约数的个数是
d(n)=∏i=1k(ai+1)=(a1+1)(a2+1)⋯(ak+1)d(n)=\prod_{i=1}^k(a_i+1)=(a_1+1)(a_2+1)\cdots(a_k+1) d(n)=i=1∏k(ai+1)=(a1+1)(a2+1)⋯(ak+1)
证明:
p1a1p_1^{a_1}p1a1 的约数有 p10,p11,p12,⋯,p1a1p_1^0,p_1^1,p_1^2,\cdots,p_1^{a_1}p10,p11,p12,⋯,p1a1 共 a1+1a_1+1a1+1 个,同理 pkakp_k^{a_k}pkak 的约数有 ak+1a_k+1ak+1 个。
由乘法原理,nnn 的约数个数就是 (a1+1)(a2+1)⋯(ak+1)(a_1+1)(a_2+1)\cdots(a_k+1)(a1+1)(a2+1)⋯(ak+1)
代码:
其实和质因数分解很相似,只要会质因数分解,就会求因数个数
int num_divisors(int n) {int res = 1;for (int i = 2; i <= n / i; ++i) {if (n % i == 0) {int s = 0;while (n % i == 0) {n /= i;++s;}res *= s + 1;}}if (n > 1) res *= 2;return res;
}
对于一个大于 111 的正整数 nnn 可以分解质因数:
n=∏i=1kpiai=p1a1⋅p2a2⋅⋯⋅pkakn=\prod_{i=1}^kp_i^{a_i}=p_1^{a_1}\cdot p_2^{a_2}\cdot\cdots\cdot p_k^{a_k} n=i=1∏kpiai=p1a1⋅p2a2⋅⋯⋅pkak
n 的约数之和是
σ(n)=(p10+p11+p12+⋯+p1a1)(p20+p21+p22+⋯+p2a2)⋯(pk0+pk1+pk2+⋯+pkak)\sigma(n)=(p_1^0+p_1^1+p_1^2+\cdots+p_1^{a_1})(p_2^0+p_2^1+p_2^2+\cdots+p_2^{a_2})\cdots(p_k^0+p_k^1+p_k^2+\cdots+p_k^{a_k}) σ(n)=(p10+p11+p12+⋯+p1a1)(p20+p21+p22+⋯+p2a2)⋯(pk0+pk1+pk2+⋯+pkak)
等比数列求和,上式可以写成
σ(n)=p1a1+1−1p1−1×p2a2+1−1p2−1×⋯×pkak+1−1pk−1\sigma(n)=\frac{p_1^{a_1+1}-1}{p_1-1}\times\frac{p_2^{a_2+1}-1}{p_2-1}\times\cdots\times\frac{p_k^{a_k+1}-1}{p_k-1} σ(n)=p1−1p1a1+1−1×p2−1p2a2+1−1×⋯×pk−1pkak+1−1
代码:
int sum_divisors(int n) {int res = 1;for (int i = 2; i <= n / i; ++i) {if (n % i == 0) {int s = i;while (n % i == 0) {n /= i;s *= i;}res *= (s - 1) / (i - 1);}}if (n > 1) res *= (n * n - 1) / (n - 1);return res;
}
欧几里得算法
欧几里得算法又称辗转相除法,计算公式为 gcd(a,b)=gcd(b,amodb)\gcd(a,b)=\gcd(b,a\mod b)gcd(a,b)=gcd(b,amodb)
假如需要求 199719971997 和 615615615 两个正整数的最大公约数,用欧几里得算法,是这样进行的:
1997÷615=3(余152)1997 ÷ 615 = 3 (余 152)1997÷615=3(余152)
615÷152=4(余7)615 ÷ 152 = 4(余7)615÷152=4(余7)
152÷7=21(余5)152 ÷ 7 = 21(余5)152÷7=21(余5)
7÷5=1(余2)7 ÷ 5 = 1 (余2)7÷5=1(余2)
5÷2=2(余1)5 ÷ 2 = 2 (余1)5÷2=2(余1)
2÷1=2(余0)2 ÷ 1 = 2 (余0)2÷1=2(余0)
至此,最大公约数为 111
以除数和余数反复做除法运算,当余数为 000 时,取当前算式除数为最大公约数,所以就得出了 199719971997 和 615615615 的最大公约数 111。
代码:
int gcd(int a, int b) {return b ? gcd(b, a % b) : a;
}