约数之和 约数个数 最大公约数

约数公式

关于约数,有两个公式,一个是约数个数公式,一个是约数之和公式

约数个数

\(n\)个数相乘的因数个数,答案对 \(10^9+7\) 取模

公式

\[\begin{align} N = &p_1^{n_1} * p_2^{n_2} *\dots * p_k^{n_k}\\ 因数个数 = &(n_1+1)(n_2+1)\dots(n_k+1)\\ &因为 任何一个 约数 d可以表示成\\ d=&p_1^{m_1} * p_2^{m_2} * \dots * p_k^{m_k},0\leq m_i\leq m_i \end{align} \]

想法

小学奥数题,指数加一再连乘

把一个数分解质因数,再把每一个质因数的指数加一乘起来

比如一个数\(N\)分解成\(P_1^{n_1} \times P_2^{n_2} \times \dots\times P_k^{n_k}\) 通过组合来理解
如果两项的\(n_i\)不同,那么就会产生不同的因数
所以\(N\)的因数个数和指数\(n_i\)的选法个数相等
对于\(P_i\)的指数\(n_i\),可以选择\(0,1,2,3 \dots i\)个,也就是\(i+1\)种选法
所以每个\(P_i\)的选法\(i+1\)乘起来就是总的选法,也就是\(N\)的因数个数

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>

using namespace std;
typedef long long LL;

const int mod = 1e9+7;

int main()
{
    int n;
    scanf("%d", &n);
    
    unordered_map<int, int> primes; // 用哈希表存,数组存不下
    
    while (n -- )
    {
        int x;
        scanf("%d", &x);
        // 分解质因数
        for(int i = 2; i <= x / i; i++)
        {
            while(x % i == 0)
            {
                x /= i;
                primes[i]++;
            }
        }
        if(x > 1) primes[x] ++;
    }
    
    LL res = 1; // 存答案
    
    for(auto t : primes) res = res * (t.second + 1) % mod; // 质数加一再连乘 记得模mod
    
    cout << res << endl;
    
    return 0;
}

约数之和

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

公式

\[ (p_1^0 + p_1^1 + \dots + p_1^{c_1}) \times \dots \times (p_k^0 + p_k^1 + \dots + p_k^{c_k}) \]

证明

证明:算术基本定理

一个数\(N\)只能被拆分为唯一的\(p_1^{c_1} \times p_2^{c_2} \times \dots \times p_k^{c_k}\)
所以\(N\)的每个因数就是\(N\)分解质因数后因指数的每一种选法
看公式,在每个括号里面都是\(p_i\)的一种选法,与另一些括号里的\(p_i\)相乘,就是每一个因数,根据乘法分配律,上面的公式就是所有因数之和

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>

typedef long long LL; // long long类型
using namespace std;

const int mod = 1e9 + 7; // 模

int main()
{
    int n;
    scanf("%d", &n);
    unordered_map<int, int> primes; // 哈希表
    
    while (n -- )
    {
        int x;
        scanf("%d", &x);
        // 分解质因数
        for(int i = 2; i <= x / i; i++)
            while(x % i == 0) 
		x /= i, primes[i] ++;
        
        if(x > 1) primes[x] ++;
    }
    
    
    LL res = 1;
    for(auto t : primes) // 迭代器简单写法(auto C++ 11标准)
    {
        LL a = t.first, b = t.second;
        LL temp = 1;
        // 公式
        while(b -- )
            temp = (temp * a + 1) % mod;
        
        res = res * temp % mod;
    }
    
    cout << res << endl;
    
    return 0;
}

最大公约数

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

想法

1.辗转相除
2. algorithm库__gcd()这是最快的

思路

两个数的gcd等于其中较小的数字和二者之间余数的gcd

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int gcd(int a, int b)  // 欧几里得算法
{
    return a % b ? gcd(b, a % b) : b;
    // return b ? gcd(b, a % b) : a;
}

int main()
{
    int n;
    scanf("%d", &n);
    while (n -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);   
        
        cout << gcd(a, b) << endl;
        // cout << __gcd(a, b) << endl;
    }

    return 0;
}
posted @ 2022-07-24 00:01  MoyouSayuki  阅读(72)  评论(0编辑  收藏  举报
:name :name