信息学奥赛中的数学知识——约数

约数个数

任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积:
N = p 1 a 1 × p 2 a 2 × p 3 a 3 . . . p n a n N=p_1^{a_1}×p_2^{a_2}× p_3^{a_3} ... p_n^{a_n}N=p1a1×p2a2×p3a3...pnan这里p 1 < p 2 < p 3 . . . < p n p_1 < p_2 < p_3... < p_np1<p2<p3...<pn均为质数,其中指数a i a_iai是正整数。这样的分解称为 N 的标准分解式。

N 的约数个数 =( a 1 + 1 ) × ( a 2 + 1 ) × ( a 3 + 1 ) × . . . × ( a n + 1 ) (a_1+1) × (a_2 + 1) × (a_3 +1) × ... × (a_n + 1)(a1+1)×(a2+1)×(a3+1)×...×(an+1)

证明

N NN可以分解质因数:
N = p 1 a 1 × p 2 a 2 × p 3 a 3 . . . p n a n N=p_1^{a_1}×p_2^{a_2}× p_3^{a_3} ... p_n^{a_n}N=p1a1×p2a2×p3a3...pnan
p 1 a 1 p_1^{a_1}p1a1由约数定义可知的约数有:p 1 0 , p 1 1 , . . . p 1 a 1 p_1^0,p_1^1,...p_1^{a_1}p10,p11,...p1a1,共( a 1 + 1 ) (a_1+1)(a1+1)个;同理p 2 a 2 p_2^{a_2}p2a2的约数有( a 2 + 1 ) (a_2+1)(a2+1)个;……;p k a k p_k^{a_k}pkak的约数有( a k + 1 ) (a_k+1)(ak+1)个。

故根据乘法原理:N NN的约数的个数就是:( a 1 + 1 ) × ( a 2 + 1 ) × . . . × ( a n + 1 ) (a_1+1)\times(a_2+1)\times...\times(a_n+1)(a1+1)×(a2+1)×...×(an+1)

模板问题

给定 n nn 个正整数 a i a_iai,请你输出这些数的乘积的约数个数,答案对 1 0 9 + 7 10^9+7109+7 取模。

输入格式

第一行包含整数 n nn
接下来 n nn 行,每行包含一个整数 a i a_iai

输出格式

输出一个整数,表示所给正整数的乘积的约数个数,答案需对 1 0 9 + 7 10^9+7109+7 取模。

数据范围
1 ≤ n ≤ 100 1≤n≤1001n100,
1 ≤ a i ≤ 2 × 1 0 9 1≤a_i≤2×10^91ai2×109

输入样例

3
2
6
8

输出样例

12

代码实现

#include <iostream>
#include <map>
using namespace std;

/*
如果 N = p1^c1 * p2^c2 * ... *pk^ck
约数个数: (c1 + 1) * (c2 + 1) * ... * (ck + 1)
*/
const int mod = 1e9 + 7;
typedef long long LL;
int main()
{
    int n;
    cin >>  n;
    map<int, int> h;
    while(n --)
    {
        int x;
        cin >> x;
        for(int i = 2; i <= x / i; i ++)
        {
            while(x % i == 0)
            {
                h[i] ++;
                x /= i;
            }
        }
        // 任何一个数字x,最多只包含一个大于sqrt(x)的质因子
        if(x > 1) h[x] ++;
    }

    int res = 1;
    for(map<int, int>::iterator it = h.begin(); it != h.end(); it ++)
    {
        res = (LL) res * (it -> second + 1) % mod;
    }
    cout << res << endl;
    return 0;
}

约数之和

N 的约数之和 =( p 1 0 + p 1 1 + p 1 2 + . . . + p 1 a 1 ) × ( p 2 0 + p 2 1 + p 2 2 + . . . + p 2 a 2 ) × . . . × ( p n 0 + p n 1 + p n 2 + . . . + p n a n ) (p_1^0+p_1^1+p_1^2+...+ p_1^{a_1}) × (p_2^0 + p_2^1 + p_2^2 + ... +p_2^{a_2})×... × (p_n^0 + p_n^1 + p_n^2 + ... + p_n^{a_n})(p10+p11+p12+...+p1a1)×(p20+p21+p22+...+p2a2)×...×(pn0+pn1+pn2+...+pnan)

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
//divs[i] = j 表示因子i的个数为j
unordered_map<int, int> divs;

int main(){
    int n;
    cin>>n;
    while(n--){
        int x; cin>>x;
        //求x的约数,及其个数
        for(int i = 2; i <= x / i; i++){
            while(x % i == 0) {
                divs[i]++;
                x /= i;
            }
        }
        if(x > 1) divs[x]++;

    }
    long long res = 1;
    for(auto d : divs){
        int p = d.first, a = d.second;

        long long t = 1;
        // t[1] = 1 + p^1
        // t[2] = 1 + (1 + p) * p  = 1 + p^1 + p^2
        // t[k - 1] = 1 + p^1 + p^2 + ... + p^{k-1}
        // t[k] = 1 + t[k-1] * p= 1 + ( 1 + p^1 + p^2 + p^{k-1}) * p = 1 + p^1 + p^2 +...+ p^{k-1} + p^k
        while(a--) 
            t = (1 + t * p) % mod; 

        res = res * t % mod;

    }
    cout<<res<<endl;

    return 0;
}


版权声明:本文为qiaoxinwei原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。