概念
约数:也叫因数。若a%b==0,则称b是a的因数。
对于一个数N,可以构造N = p1^a1 + p2^a2 +...+ pn^an。
其中,p是底数,也必须是质因数,比如在分解12 = 2×2×3 = 2^2+3^1的式子中,2和3就是底数;a是指数,是底数出现的次数,比如2的指数是2,3的指数是1。
分解质因数
用一个unordered_map保存质因数,键是质因数的底数,值是质因数的指数,也就是底数出现的次数。
//对x进行质因数分解
unordered_map<int,int> m; //注意头文件#include<unordered_map>
//键表示底数,值表示指数
for(int i=2; i<=x/i ;i++)
{
while(x%i==0)
{
m[i]++; //i的指数+1
x/=i;
}
}
if(x>1) m[x]++; //x也是底数
约数个数
【定理】约数个数 = (a1+1) * (a2+1) * ... * (an+1) 。
例如12=2^2 + 3^1,约数是1,2,3,4,6,12,通过(2+1)*(1+1)得到约数个数为6。
//分解完质因数后保存在m(m是一个unordered_map)中
int ans=1; //注意不能写0
for(auto i:m)
{
int a=i.first,b=i.second; //键(first)是底数,值(second)是指数
ans=ans*(b+1);
}
cout<<ans;
约数之和
【定理】约数之和 = (p1^0+p1^1+...+p1^a1) * (p2^0+p2^1+...+p2^a2) * ... * (pn^0+pn^1+...+pn^an)。
例如12=2^2 + 3^1,约数之和为 (1+2+4) *(1+3) = 28。
//分解完质因数后保存在m(m是一个unordered_map)中
int ans=1; //注意不能写0
for(auto i:m)
{
int a=i.first,b=i.second;
int t=1; //1是a^0
for(int j=1;j<=b;j++) t+=pow(a,j);
ans=ans*t;
}
cout<<ans;
辗转相除法
辗转相除法,又称欧几里得算法,用来求两个数的最大公约数。
【定理】被除数与除数的最大公约数,就是除数与余数的最大公约数。
即gcd(a, b) = gcd(b, a%b)。我们可以递归地实现这一步骤。
//返回a和b的最大公约数
int gcd(int a, int b)
{
if (b == 0) return a;
else return gcd(b, a % b);
}