约数个数 & 约数之和

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 @ 2022-06-26 20:07  lucky_light  阅读(278)  评论(0编辑  收藏  举报