acwing算法基础课/算法竞赛进阶指南 约数
首先考虑分解质因数的算法:
在枚举因子时,不停将x除以i直到x不是i的倍数,这样每枚举到一个合数i,x中所有i的因子都已经被除掉了,i不可能成为x的因子。
这样,保证了满足第六行x%i==0
的i一定是质因数,顺便统计出了每个质因数的指数。
有一个显然的结论:x中至多有一个大于\(\sqrt{x}\)的质因子,而且它的次数一定是1。(反证即可)
所以可以只循环到i <= x/i
,如果退出循环后x>1,特判x是原数的一次质因子即可。
我们记每个质因子是\(p_{i}\),次数是\(c_{i}\)
由乘法原理易得:
由于每个质因子的次数可以选\(0\)到\(c_{i}\),故约数的个数是
\[\prod_{i=1}^{n} \left ( c_{i}+1 \right )
\]
考虑每个约数可以选每个质因数的\(0\)到\(c_{i}\)次方相乘,所有约数的和为
\[\prod_{i=1}^n (\sum_{j=0}^{c_{i}}p_i^j)
\]
- 分解质因数
#include <iostream>
using namespace std;
void solve(int x) {
for (int i = 2; i <= x / i; i++) {
if (x % i == 0) {
int p = 0;
while (x % i == 0) {
x /= i;
p++;
}
printf("%d %d\n", i, p);
}
}
if (x > 1) printf("%d 1\n", x);
printf("\n");
}
int main() {
int T, x;
scanf("%d", &T);
while (T--) {
scanf("%d", &x);
solve(x);
}
return 0;
}
- 约数个数
#include <iostream>
#include <unordered_map>
using namespace std;
const int mod = 1e9 + 7;
int main() {
unordered_map<int, int> hash;
int n, x;
scanf("%d", &n);
while (n--) {
scanf("%d", &x);
for (int i = 2; i <= x / i; i++) {
while (x % i == 0) {
x /= i;
hash[i]++;
}
}
if (x > 1) hash[x]++;
}
long long ans = 1;
for (auto u : hash) ans = ans * (u.second + 1) % mod;
printf("%lld", ans);
return 0;
}
- 约数之和
#include <iostream>
#include <unordered_map>
using namespace std;
const int mod = 1e9 + 7;
int main() {
unordered_map <int, int> hash;
int n, x;
scanf("%d", &n);
while (n--) {
scanf("%d", &x);
for (int i = 2; i <= x / i; i++) {
while (x % i == 0) {
x /= i;
hash[i]++;
}
}
if (x > 1) hash[x]++;
}
long long ans = 1;
for (auto u : hash) {
long long t = 1, sum = 1;
for (int i = 1; i <= u.second; i++) {
t = t * u.first % mod;
sum = (sum + t) % mod;
}
ans = ans * sum % mod;
}
printf("%lld", ans);
return 0;
}