约数个数 & 约数之和

c++

约数个数 & 约数之和

/*
*
* 约数个数 & 约数之和
*
* 问题描述:
* 给定数字 x,问数字 x 的约数个数和约数求和的结果。
*
* 算法思路1:
* 最朴素的做法,使用试除法求出 `x` 的所有约数,那么个数以及约数和就可以得到。
* 复杂度 O(\sqrt(N))
* 算法思路2:
* 算术基本定理:
* 又称为自然数唯一分解定理,任一大于1的自然数都可分解成若干质因数的连乘积,如果不计各质因数的顺序,这种分解是唯一的。
* 我们假设 x 可以表示为
* $x=p_1^{a_1} p_2^{a_2} ... p_k^{a_k}$,其中 $p_1 \le p_2 \le \cdots \le p_k, 任意i \in[1,k], a_i \ge 1$
* p_1, p_2, ..., p_k 组成了 x 的质因数集合。
* 那么由算数基本定理可得:
* num_divisors = (a_1 + 1) (a_2 + 1) ... (a_n + 1) ------------- 公式(1)
* sum_divisors = (1 + p_1 + p_1^2 + ... + p_1^{a_1}) (1 + p_2 + p_2^2 + ... + p_2^{a_1})
* ... (1 + p_k + p_k^2 + ... + p_k^{a_k}) ------------- 公式(2)
* 其中约数的数量完全可以排列组合得到,约数求和恰好可以由公式(2)拆解得到
* 复杂难度仅仅在找质因数上。复杂度 O(\sqrt(N)),但是和算法思路1不同,这是最坏复杂度,基本上是不会达到O(\sqrt(N))的。
*/
#include <cstdio>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <unordered_map>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
const int MOD = 1e9 + 7;
int n;
vector<PII> prime_divisors;
unordered_map<int, int> prime_to_idx;
void get_prime_divisors(int x) {
int cnt = 0, cur;
for (int i = 2; i <= x / i; i ++ ) {
if (x % i == 0) {
cnt = 0;
while (x % i == 0) {
x /= i;
cnt += 1;
}
if (prime_to_idx.count(i) == 0) {
prime_to_idx[i] = prime_divisors.size();
prime_divisors.push_back(PII(i, 0));
}
cur = prime_to_idx[i];
prime_divisors[cur].second += cnt;
}
}
if (x != 1) {
if (prime_to_idx.count(x) == 0) {
prime_to_idx[x] = prime_divisors.size();
prime_divisors.push_back(PII(x, 0));
}
cur = prime_to_idx[x];
prime_divisors[cur].second += 1;
}
}
LL get(int a, int b) {
LL sum = 1;
for (int i = 1; i <= b; i ++ ) {
sum = (sum * a + 1) % MOD;
}
// printf("%d %d %lld\n", a, b, sum);
return sum;
}
LL get_divisor_sum(vector<PII> prime_divisors) {
LL res = 1ll;
for (int i = 0; i < prime_divisors.size(); i ++ ) {
res = res * get(prime_divisors[i].first, prime_divisors[i].second) % MOD;
}
return res;
}
LL get_divisor_num(vector<PII> prime_divisors) {
LL res = 1ll;
for (int i = 0; i < prime_divisors.size(); i ++ ) {
res = res * (prime_divisors[i].second + 1) % MOD;
}
return res;
}
void show() {
printf("***********************\n");
for (int i = 0; i < prime_divisors.size(); i ++ ) {
printf("%d %d\n", prime_divisors[i].first, prime_divisors[i].second);
}
printf("***********************\n");
}
int main()
{
scanf("%d", &n);
int x;
while(n -- ) {
scanf("%d", &x);
get_prime_divisors(x);
}
// show();
printf("%lld\n", get_divisor_sum(prime_divisors));
return 0;
}
posted @   lucky_light  阅读(333)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示