约数相关算法 C++实现

题目一 试除法求约数

图源ACWING

题解思路

  1. 用 i 遍历1到sqrt(n);
  2. 将其中能整除的数放入结果中,同时把 n / i 也放入结果集(约数总是成对出现);
  3. 特判:如果n / i == i ,只放一个进去;

代码实现

#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>

using namespace std;

void divi(int n)
{
    int sq = sqrt(n);
    vector<int>q;
    
    for(int i = 1;i <= sq;i ++ )
    {
        if(n % i == 0)
        {
            q.push_back(i);
            if(n / i == i)
            {
                continue;
            }
            q.push_back(n / i);
        }
    }
    
    sort(q.begin(), q.end());
    
    for(auto a : q)
    {
        cout << a << ' ';
    }
    
    cout << endl;
}

int main()
{
    int n, a;
    
    cin >> n;
    
    while(n -- )
    {
        scanf("%d", &a);
        divi(a);
    }
    return 0;
}

题目二 求约数个数

图源ACWING

解题思路

数学公式:
一个数N 可以写成:N = (p1x1)(p2x2)(p3x3)…(pkxk),其中pi为质数,xi为正整数。则N的约数个数为:(x1+1)(x2+1)(x3+1)…(xk+1)

例如:12 可以分解为:22 * 31 ,则其约数个数 = (2 + 1)(1 + 1) = 6个

  1. 分解质因数;
  2. 带入求约数个数的公式;

代码实现

#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<cmath>

using namespace std;

unordered_map<int, int> map;
long long res = 1;
const int N = 1e9 + 7;

int main()
{
    int n, x, sq;
    
    cin >> n;
    
    while(n -- )
    {
        scanf("%d", &x);
        
        sq = sqrt(x);
        
        for(int i = 2;i <= sq;i ++ )
        {
            while(x % i == 0)
            {
                map[i] ++ ;
                x /= i;
            }
        }
        
        if(x > 1)
        {
            map[x] ++ ;
        }
    }
    
    for(auto i : map)
    {
        res = res * (i.second + 1) % N;//在累乘过程中就取模,防止超出long long 大小限制;
    }

    cout << res;
    return 0;
}

题目二 求约数之和

图源ACWING

题解思路

数学公式
正整数n可以写成:n = p1e1 p2e2 p3e3 … pkek ;
则其余数之和等于:(1 + p1 + p12 + p13 + … + p1e1)(1 + p2 + p22 + p23 + … + p2e2)…(1 + pk + pk2 + pk3 + … + pkek);

  1. 分解质因数;
  2. 带入公式求解;

代码实现

#include<iostream>
#include<algorithm>
#include<cmath>
#include<unordered_map>

using namespace std;

const int N = 1e9 + 7;

unordered_map<int ,int> map;//质因子为key,幂次为value
typedef long long LL;

int main()
{
    int n, m, sq;
    
    cin >> n;
    
    while (n -- )
    {
        scanf("%d", &m);
        
        sq = sqrt(m);
        
        for (int i = 2;i <= sq;i ++ )
        {
            while (m % i == 0)
            {
                map[i] ++ ;
                m /= i;
            }
        }
        
        if (m > 1)
        {
            map[m] ++ ;
        }
    }
    
    LL res = 1;
    
    for (auto i : map)
    {
        LL a = i.first;
        LL b = i.second;
        LL t = 1;
        //实现(1 + pk + pk^2^ + pk^3^ + ... + pk^ek^)的步骤
        while (b -- )
        {
            t = (t * a + 1) % N;
        }
        //累乘求结果
        res = res * t % N;
    }
    
    cout << res;
    return 0;
}

算法具体解析

在这里插入图片描述
原链接:https://www.acwing.com/solution/content/248459/

题三 求最大公约数

图源ACWING

解题思路

辗转相除法

(a, b) = (a % b, b) = (b, a %b)
相当于每一步都把数字进行缩小,等式右边就是每一步对应的缩小结果。
对(a, b)连续使用辗转相除,直到小括号内右边数字为0,小括号内左边的数就是两数最大公约数

代码实现

#include<iostream>
#include<algorithm>

using namespace std;

void gcb(int a, int b)
{
    if(b == 0)
    {
        cout << a << endl;
        return ;
    }
    else
    {
        gcb(b, a % b);
    }
}

int main()
{
    int n, a, b;
    
    cin >> n;
    
    while(n -- )
    {
        scanf("%d%d", &a, &b);
        gcb(a, b);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值