质因数和约数

质因数和约数

1.分解质因数

​ 对于分解质因数这类问题 首先 我们应该知道

  • 什么是质因数:质因数,我们可以理解为 对于给定一个数字 n 我们可以用
    n = p 1 α 1 ∗ p 2 α 2 ∗ … ⋯ ∗ p x α x ( 1 ) n=p_1^{\alpha_1}*p_2^{\alpha_2}*\ldots\dots*p_x^{\alpha_x} (1) n=p1α1p2α2…⋯pxαx1
    这个公式 来表示 其中 p为一个质数 α \alpha α可以为0到正无穷的数字 了解了这个我们可以看一下 我们的分解质因数的代码
#include<iostream>
using namespace std;
int n;
void divide(int x)
{
    for(int i=2;i<=x/i;i++)
    {
        
        if(x%i==0)
        {
            int s=0;
            while(x%i==0)
            {   
                x=x/i;
                s++;

            }
             cout<<i<<" "<<s<<endl;

        }
       

    }
    if(x>1)
    {
        cout<<x<<" "<<1<<endl;
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){


        int x;
        cin>>x;
        divide(x);
        cout<<endl;

    }
    return 0;
}

输入
2
6
8

输出
2 1
3 1

2 3

​ 对于这个代码 我们分解质因数的就是从前面到后面遍历所有的数(其实也相当于遍历所有的质数 因为 一个合数肯定可以分解为 多个质数相乘 ),遍历到 n \sqrt{n} n 因为 质因数 不可能比 n \sqrt{n} n 大 不然这两个质因数相乘大于n 矛盾

​ 需要注意的是 在我们的代码当中 传进去的形式参数 x是不断减少的 因为我们分解质因数的过程其实就是 去找上面那个公式(1)当中 的p和 α \alpha α的过程 方程两边同时除以一个数不会影响我们最后的求解

 if(x>1)
    {
        cout<<x<<" "<<1<<endl;
    }

​ 对于这段代码的使用 有两种情况 一种是 我们的 x本身就是质数 遍历完 之后没有找到质因数 还有一种就是我们不断减少 我们的x过程中最大的那一个p的系数是1 也就是相当于 最大的那个p就是一个单独的质数 那么这时候和第一种情况相同 。 可以试一下 12的例子 理解会深刻一点

2.试除法求一个数字的约数

​ 约数就是对于一个数 n 所有能被他整除的数都是他的约数

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> divide(int x)
{
    vector<int > res;
    for(int i=1;i<=x/i;i++)
    {   
        if(x%i==0)
        {
            res.push_back(i);
            // 防止出现 i*i=x重复添加
            if(x/i!=i)
            {   
                res.push_back(x/i);

            }

        }


    }
    sort(res.begin(),res.end());
    return res;


}
int main()
{   
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        auto res=divide(x);
        for(auto p:res)
        {
            cout<<p<<" ";


        }
        cout<<endl;

    }


    return 0;
}
输入
2
6
8
输出 
1 2 3 6 
1 2 4 8 

​ 约数我们可以理解 公式(1) 当中 对于每个 α i \alpha_i αi 取0到上界 的不同值的排列组合 这样我们就可以的到所有的 约束的个数 也就是下一个题目。

3.约数的个数

​ 对于约数的个数 在2中已经解释了 约数个数的公式 具体公式如公式2
a n s = ( α 1 + 1 ) ∗ ( α 2 + 1 ) … … ( α k + 1 ) ans=({\alpha_1+1})*({\alpha_2+1})\ldots\ldots({\alpha_k+1}) ans=(α1+1)(α2+1)……(αk+1)
因为 每个 α \alpha α可以取 0到 α \alpha α的所有的值 所以 有 α + 1 \alpha+1 α+1个值可以选择 每个都是 那么利用排列组合当中的乘法原则 他们相乘 就可以得到我们的ans。

​ 我们可以看看题目 这个题目就是求给定n个数 求他们的乘积的约数的个数和

​ 我们可以这么理解 乘积也是一个数 也一定是 符合公式(1)的 那么 我们只需要分开来求 成绩的 每个 α \alpha α即可 因为
p α ∗ p β = p α + β p^\alpha *p^\beta=p^{\alpha+\beta} pαpβ=pα+β
​ 所以 我们 先分开求 然后把他们各自p对应的 α \alpha α 加起来 就可以得到最终的 α \alpha α

coding:

注意undermap的使用

#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
const int mod=1e9+7;
unordered_map<int ,int>  ps;
void diviede(int x)
{
    // 分解质因数的步骤 
    for(int i=2;i<=x/i;i++)
    {
        if(x%i==0)
        {
            while(x%i==0)
            {
                x=x/i;
                ps[i]++;
            }

        }



    }
    if(x>1)
    {
        ps[x]++;

    }


}

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        diviede(x);


    }
    long long int ans=1;   
    for(auto p:ps)
    {
        ans=ans*(p.second+1);
        ans=ans%mod;

    }
    cout<<ans<<endl;


    return 0;
}

输入 
3
2
6
8

输出

12

4.约数的和

​ 约数的和其实也是一个公式
a n s = ( p 1 0 + p 1 1 + … + p 1 α 1 ) ∗ ( p 2 0 + p 2 1 + … + p 2 α 2 ) ∗ … ∗ ( p k 0 + p k 1 + … + p k α k ) ans=(p_1^0+p_1^1+\ldots+p_1^{\alpha_1})*(p_2^0+p_2^1+\ldots+p_2^{\alpha_2})*\ldots*(p_k^0+p_k^1+\ldots+p_k^{\alpha_k}) ans=(p10+p11++p1α1)(p20+p21++p2α2)(pk0+pk1++pkαk)

​ 这个公式要理解 我们可以把它展开 发现是 约数个数项多项式的和 每一个 多项式都会是一个 约数 他们相加自然 是所有约数的和 。

coding:

#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
const int mod=1e9+7;
unordered_map<int ,int>  ps;
void diviede(int x)
{
    // 分解质因数的步骤 
    for(int i=2;i<=x/i;i++)
    {
        if(x%i==0)
        {
            while(x%i==0)
            {
                x=x/i;
                ps[i]++;
            }

        }



    }
    if(x>1)
    {
        ps[x]++;

    }


}

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        diviede(x);


    }
    long long int ans=1;   
    for(auto p:ps)
    {
       long long int  res=1;
        long long int a=p.first;
        long long int b=p.second;
        // 注意p的0次方  因为 b等于0的时候就不进了
        while(b--)
        {
            res=(res*a+1)%mod;

        }
        ans=ans*res;
        ans=ans%mod;

    }
    cout<<ans<<endl;


    return 0;
}

​ 注意我们 在 在求p的0次方到p的n次方的时候所使用的方法 这里 res表示 这个总和 执行一次 变为 p+1 执行两次 变为 p 2 + p + 1 p^2+p+1 p2+p+1了 依次类推即可 。

5.求最大公约数

直接__gcd()就完事了 然后 这个需要头文件 algorithm 欧几里得算法 太难了QAQ

coding:

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

int main()
{

    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        cin>>x>>y;
        cout<<__gcd(x,y)<<endl;        
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值