4.数学知识——约数

结合网上的各位老师的思想提炼总结~欢迎大家交流学习~

文章目录

  • 求最大公约数
  • 试除法求约数
  • 求约数个数
  • 求约数之和
  • 注意

一、求最大公约数

1.什么是最大公约数?多个整数的共有约数中的最大约数,记作gcd(a,b)吧

2.怎么求最大公约数?求最大公约数有很多方法,今天来分享一下其中的辗转相减法和辗转相除法。用gcd(a,b)来表示a和b的最大公约数,则gcd(a,b)=gcd(a,ka+b)(a,b,k都是自然数)。理由如下,如果p是a和ka+b的公约数,说明p是a的约数,要想p也是ka+b的约数,则p也得是b的约数,所以p是a和b的公约数,因此他们的最大公约数也相等。

比如:gcd(78,14)=gcd(64,14)=gcd(50,14)=gcd(36,14)=gcd(22,14)=gcd(8,14)=gcd(8,6)=gcd(2,6)=gcd(2,4)=gcd(2,2)=gcd(0,2)=2                                                                             但迭代相减法步数比较多,因此可以gcd(78,14)=gcd(14*5+8,14)=gcd(8,14)=gcd(8,8*1+6)=gcd(8,6)=gcd(6*1+2,6)=gcd(2,6)=gcd(2,2*1+4)=gcd(2,4)=gcd(2,2*1+2)=gcd(2,2)=gcd(2,2*1+0)=gcd(2,0),由此得到迭代相除法gcd(a,b)=gcd(a%b,b)=gcd(b,a%b)

3.core idea:对(a,b)连续使用辗转相除,直到括号右边数字为0,括号左边即是两数最大公约数

4.代码如下:

   //小括号左边放除数,右边放约数
int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}
 //辗转相除,直到小括号内右边数为0,小括号内左边数为最大公约数

二、试除法求约数

1.什么是约数?a%b==0,则b是a 的约数

2.core idea:枚举[1,^{\sqrt{x }}],如果x%i==0,则说明i是x的约数,需要存储进数组。那另一个约数x/i(x/i!=i)也需要存储进数组。

3.代码如下:

vector<int> get_divisors(int x)
{
    vector<int> res;//存储x的约数的数组
    for (int i = 1; i*i<=x; i ++ )
        if (x % i == 0)
        {
            res.push_back(i);
            if (i != x / i) res.push_back(x / i);
        }
    sort(res.begin(), res.end());//对x的约数们排序
    return res;
}

三、 求约数个数

 1.  x=p_{1}^{e_{1}}\times p_{2}^{e_{2}}\times.....\times p_{k}^{e_{k}}

    约数个数= (e_{1}+1)\times (e_{2}+1)\times .....\times (e_{k}+1)                                                                                       

  比如分解质因子12=2^{2}\times 3^{1},12的质因子有2,3。12的约数有1,2,3,4,12这六个。                                                        

 因此2可以取0/1/2个,3可以取0/1个,再组合成6种情况。

2.core idea:先找到x的所有质因数和每个质因数的个数并存储起来(分解质因数 ),再套用红字公式

3.代码如下:

​
​
​
​typedef long long LL;

const int mod = 1e9 + 7;

 unordered_map<int, int> a;//{p,e}  p为x的某个质因数,用.first表示  e为某个质因数p的个数,用.second表示

void decompose(int x)//分解x的质因数
{
   for(int i=2;i*i<=x;i++)
  {
     while(x%i==0)a[i]++,x/=i;
  }
    if(x>1)a[x]++;//x>1,说明这就是那个大于根下x的质因子
}
 
​---------------------------------------------------------------
LL res=1;//约数个数,初始化为1用于累乘
for(auto m:a){res=res*(m.second+1)%mod;}//取模是为了防止结果溢出,通常在处理大数时使用
cout<<res;

​

​

​

 四、求约数之和

1.x=p_{1}^{e_{1}}\times p_{2}^{e_{2}}\times ....p_{k}^{e_{k}}

   

 x的约数之和=(x的每个质因子的约数之和)的乘积,其中(x的每个质因子的约数之和)用等差数列求和

2..core idea:先找到x的所有质因数和每个质因数的个数并存储起来(分解质因数 ),再套用红字公式

3.代码如下:

​
​

​
​typedef long long LL;

const int mod = 1e9 + 7;

 unordered_map<int, int> a;//a[i]为第i个{p,e}  p为x的某个质因数,用.first表示  e为某个质因数p的个数,用.second表示

void decompose(int x)//分解x的质因数
{
   for(int i=2;i*i<=x;i++)
  {
     while(x%i==0)a[i]++,x/=i;
  }
    if(x>1)a[x]++;//x>1,说明这就是那个大于根下x的质因子
}
 
​---------------------------------------------------------------
LL res=1;//x的约数之和,初始化为1用于累乘
for(auto m:a){
  LL fir=m.first,sec=m.second;
  LL t=1;//x的每个质因数的约数之和,初始化为1用于累加
  while(sec--)//模拟求和等比数列
  {
    t=(t*fir+1)%mod;
    res=res*t%mod;
  }
}//取模是为了防止结果溢出,通常在处理大数时使用
cout<<res;

​

​

​

​

​

​


注意

如果以上有未提到的概念或疑惑,可以看我之前的文章有细讲的~比如分解x的质因数这一部分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值