约数
试除法求约数
一个数的约数是成对出现的,同时只有一个大于
cpp
void get_divisors(int n) {
vector<int> 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); // avoid i * i == n
}
}
}
sort(res.begin(), res.end());
for (auto t : res) {
cout << t << " ";
}
cout << endl;
}
如何计算时间复杂度?首先思考
是所有数的约数 是所有它的倍数的约数 是所有它的倍数的约数 中每个数的约数个数之和等价于每个数的倍数之和
也就是:
期望来看,每个数的约数个数就是
总的时间复杂度为
约数个数
对于某个自然数
它的所有约数个数为(简单的乘法原理):
约数之和
由于所有的约数为
证明很显然,直接展开就可以,每一项都是约数。
核心代码:
cpp
// ...
for (auto prime : primes) {
int p = prime.first;
int a = prime.second;
long long t = 1;
while (a --) {
t = (t * p + 1) % mod;
}
res = res * t % mod;
}
这里是对于:
的扩展。
TODO:这个算法还有
最大公约数
求最大公约数的算法就是 欧几里得算法/辗转相除法。
首先我们知道,如果
我们常用 (a, b)
表示 a
和 b
的最大公约数 GCD。
辗转相除法的算法核心:(a, b) = (b, a mod b)
,证明:
a mod b
可以看作是a
不断地减去b
,直到不能减为止,不妨记为a - c * b
- 设
d
是a, b
的任何一个公约数,那么d | b, d | a - c * b
,即它是右边的公约数 - 设
d
是b, a mod b
的任何一个公约数,那么由于a = (a - c * b) + c * b
,因此d | a
,即它也是左边的公约数 - 因此左右两侧的所有公约数都相同,那么最大公约数自然也相同
核心代码:
cpp
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
有几个注意事项:
- 当
a < b
时,a mod b
得到的结果中a - c * b
中的c == 0
,下一轮调换位置 - 当
a % b == 0
时,说明此时b
就是二者的最大公约数,根据(a, b) = (b, 0)
下一轮直接输出