约数

约数

[AcWing869] 试除法求约数

题目描述

给定 \(n\) 个正整数 \(a_i\),对于每个整数 \(a_i\),请你按照从小到大的顺序输出它的所有约数。

输入格式

第一行包含整数 \(n\)

接下来 \(n\) 行,每行包含一个整数 \(a_i\)

输出格式

输出共 \(n\) 行,其中第 \(i\) 行输出第 \(i\) 个整数 \(a_i\) 的所有约数。

数据范围

\(1 \le n \le 100\),
\(1 \le a_i \le 2 \times 10^9\)

输入样例:

2
6
8

输出样例:

1 2 3 6 
1 2 4 8 

算法

给定整数 \(a\) ,那么 \(i\) 就从 \(1\) 开始遍历,和质数类似,直到 \(i \leq a / i\) 结束。

如果 \(a\) 能整除 \(i\) 的情况下,结果添加\(i\) ,若 \(a/i\) 的结果不为 \(i\) ,就继续添加 \(a/i\)

C++ 代码

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n; cin >> n;
    while (n--)
    {
        vector<int> ans;
        int a; cin >> a;
        for (int i = 1; i <= a / i; i++){
            if (a % i == 0){
                ans.push_back(i);
                if (a / i != i) ans.push_back(a / i);
            }
        }
        sort(ans.begin(), ans.end());
        for (auto i : ans)
            cout << i << " ";
        cout << endl;
    }
    return 0;
}

时间复杂度 \(O(\sqrt n)\)


[AcWing870] 约数个数

题目描述

给定 \(n\) 个正整数 \(a_i\),请你输出这些数的乘积的约数个数,答案对 \(10^9+7\) 取模。

输入格式

第一行包含整数 \(n\)

接下来 \(n\) 行,每行包含一个整数 \(a_i\)

输出格式

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

数据范围

\(1 \le n \le 100\),
\(1 \le a_i \le 2 \times 10^9\)

输入样例:

3
2
6
8

输出样例:

12

算法

基本原理约数个数定理

对于一个正整数 \(n(n>1)\) 可以分解质因数,得到

\[ {} n=\prod_{i=1}^{k}p_{i}^{a_i}=p_{1}^{a_1}\cdot p_{2}^{a_2}\cdots p_{k}^{a_k} \]

\(n\) 的正约数个数就是

\[ {} f(n)=\prod_{i=1}^{k}(a_i+1)=(a_1+1)(a_2+1)\cdots (a_k+1) \]

其中 \(a_1,a_2,...,a_k\)\(p_1,p_2,...,p_k\) 的指数。

定理证明

首先 \(n\) 分解质因数得:\(n=p_{1}^{a_1}\cdot p_{2}^{a_2}\cdots p_{k}^{a_k}\)

由约数定义可得 \(p_{1}^{a_1}\) 的约数有 \(p_{1}^{0},p_{1}^{1},p_{1}^{2},...,p_{1}^{a_1}\) ,共 \(a_1 + 1\) 个;

同理 $ p_{2}^{a_2}$ 的约数有 \(p_{2}^{0},p_{2}^{1},p_{2}^{2},...,p_{2}^{a_2}\) ,共 \(a_2 + 1\) 个;

……

同理 $ p_{i}^{a_i}$ 的约数有 \(p_{i}^{0},p_{i}^{1},p_{i}^{2},...,p_{i}^{a_i}\) ,共 \(a_i + 1\) 个。

根据乘法原理,\(n\) 的约数的个数就是 \((a_1+1)(a_2+1)\cdots (a_k+1)\) 个。

C++ 代码

my code#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int main()
{
    int n; cin >> n;
    unordered_map<int,int> hash;// hash存储质因数及其个数
    while (n--){
        int a; cin >> a;
        for (int i = 2; i <= a / i; i++){
            // 如果i是x的因子
            while (a % i == 0){
                a /= i;
                hash[i]++;
            }
        }
        // 最后没除尽的为最大因子,个数为1
        if (a > 1) hash[a]++;
    }
    auto ans = 1ll;
    // 因子利用时还有0次幂,所以有iter.second + 1个选择情况
    for (auto iter : hash) ans = ans * (iter.second + 1) % mod;
    cout << ans << endl;
    return 0;
}

时间复杂度 \(O(\sqrt n)\)


[AcWing871] 约数之和

题目描述

给定 \(n\) 个正整数 \(a_i\),请你输出这些数的乘积的约数之和,答案对 \(10^9+7\) 取模。

输入格式

第一行包含整数 \(n\)

接下来 \(n\) 行,每行包含一个整数 \(a_i\)

输出格式

输出一个整数,表示所给正整数的乘积的约数之和,答案需对 \(10^9+7\) 取模。

数据范围

\(1 \le n \le 100\),
\(1 \le a_i \le 2 \times 10^9\)

输入样例:

3
2
6
8

输出样例:

252

算法

基本原理约数和定理

对于一个正整数 \(n(n>1)\) 可以分解质因数,得到

\[n=\prod_{i=1}^{k}p_{i}^{a_i}=p_{1}^{a_1}\cdot p_{2}^{a_2}\cdots p_{k}^{a_k} \]

由正约数个数定理可知,\(n\) 的正约数个数为 \((a_1+1)(a_2+1)\cdots (a_k+1)\)

其中 \(a_1,a_2,...,a_k\)\(p_1,p_2,...,p_k\) 的指数。

那么 \(n\)\((a_1+1)(a_2+1)\cdots (a_k+1)\) 个正约数的和为

\[f(n)=(p_{1}^{0}+ p_{1}^{1}+\cdots +p_{1}^{a_1})(p_{2}^{0}+ p_{2}^{1}+\cdots +p_{2}^{a _2})\cdots(p_{k}^{0}+p_{k}^{1}+\cdots +p_{k}^{a_k}) \]

C++ 代码

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int main()
{
    int n; cin >> n;
    unordered_map<int,int> hash;// hash存储质因数及其个数
    while (n--){
        int a; cin >> a;
        for (int i = 2; i <= a / i; i++){
            // 如果i是x的因子
            while (a % i == 0){
                a /= i;
                hash[i]++;
            }
        }
        // 最后没除尽的为最大因子,个数为1
        if (a > 1) hash[a]++;
    }
    auto ans = 1ll;
    for (auto iter : hash){
        long long FI = iter.first, SE = iter.second;
        auto t = 1ll;
        // 这里类似于秦九韶算法
        while (SE--) t = (t * FI+ 1) % mod;
        ans = ans * t % mod;
    }
    cout << ans << endl;
    return 0;
}

时间复杂度 \(O(\sqrt n)\)

[AcWing872] 最大公约数

题目描述

给定 \(n\) 对正整数 \(a_i, b_i\),请你求出每对数的最大公约数。

输入格式

第一行包含整数 \(n\)

接下来 \(n\) 行,每行包含一个整数对 \(a_i,b_i\)

输出格式

输出共 \(n\) 行,每行输出一个整数对的最大公约数。

数据范围

\(1 \le n \le 10^5\),
\(1 \le a_i, b_i \le 2 \times 10^9\)

输入样例:

2
3 6
4 6

输出样例:

3
2

算法

老生常谈,辗转相除法

正整数 \(a\)\(b\) ,令 \((a,b)\)\(a\)\(b\) 的最大公约数。对 \(b\) 反复进行相除操作,如果 \(b\)\(0\) 了,结束,此时 \(a\) 即为结果。

\((a,b)\) 在每次辗转相除中都会变为 \((b,a\%b)\)

C++ 代码

#include <bits/stdc++.h>
using namespace std;

int gcd(int a, int b)
{
    return b ? gcd(b,a%b) : a;
}

int main()
{
    int n; cin >> n;
    while (n--){
        int a, b; cin >> a >> b;
        cout << gcd(a, b) << endl;
    }

    return 0;
}

时间复杂度 \(O(logn)\)

posted @ 2025-02-11 00:20  AKgrid  阅读(16)  评论(0)    收藏  举报