数学知识——约数 gcd lcm
一:约数
约数定义:约数,又称因数。整数a除以整数b(b≠0) 除得的商正好是整数而没有余数,我们就说a能被b整除,或b能整除a。a称为b的倍数,b称为a的约数。
1.试除法求约数:
若d<=sqrt(n)的d是n的约数,那么n/d也一定是n的约数,就是说n的约数是成对存在的,除了sqrt(n)本身;
因此for循环从1到n/i遍历,如果i是n的约数,则n/i也是n的约数,注意i*i=n的特殊情况。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 void get_divisors(int n) 5 { 6 vector<int>res; 7 for(int i=1;i<=n/i;i++) 8 { 9 if(n%i==0) 10 { 11 res.push_back(i); 12 if(n!=i*i)res.push_back(n/i); 13 } 14 } 15 sort(res.begin(),res.end()); 16 for(auto item:res) 17 { 18 printf("%d ",item); 19 //cout<<item<<" "; 20 } 21 puts(""); 22 } 23 int main() 24 { 25 int n; 26 scanf("%d",&n); 27 while(n--) 28 { 29 int m; 30 scanf("%d",&m); 31 get_divisors(m); 32 } 33 34 35 36 return 0; 37 }
2.约数个数:
公式:(a1+1)*(a2+1)*...*(ak+1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int mod=1e9+7; 5 6 int main() 7 { 8 int n; 9 scanf("%d",&n); 10 unordered_map<int,int>hash; 11 long long ans=1; 12 while(n--) 13 { 14 int m; 15 scanf("%d",&m); 16 for(int i=2;i<=m/i;i++) 17 { 18 while(m%i==0) 19 { 20 m/=i; 21 hash[i]++; 22 } 23 } 24 25 if(m>1)hash[m]++; 26 27 } 28 for(auto i:hash)ans=ans*(i.second+1)%mod; 29 printf("%ld",ans); 30 31 return 0; 32 }
3.约数之和:
借助了秦九韶算法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int mod=1e9+7; 5 6 int main() 7 { 8 int n; 9 scanf("%d",&n); 10 unordered_map<int,int>hash; 11 12 while(n--) 13 { 14 int m; 15 scanf("%d",&m); 16 for(int i=2;i<=m/i;i++) 17 { 18 while(m%i==0) 19 { 20 m/=i; 21 hash[i]++; 22 } 23 } 24 25 if(m>1)hash[m]++; 26 27 } 28 29 long long ans=1; 30 for(auto i:hash) 31 { 32 long long a=i.first,b=i.second; 33 long long t=1; 34 while(b--)t=(t*a+1)%mod; 35 ans=ans*t%mod; 36 } 37 38 printf("%ld",ans); 39 40 return 0; 41 }
二:最大公约数gcd O(logn)
用到了欧几里得算法(辗转相除法)
证明gcd(a,b)==gcd(b,a%b):
1.证明gcd(a,b)能推出gcd(b,a%b):
假设gcd(a,b)为m,则m|a,m|b,那么m|(a*k1+b*k2),那么设k=a/b(向下取整),则m|(a-k*b),而a-k*b就是a%b的结果。得证
2.证明gcd(b,a%b)能推出gcd(a,b):
假设gcd(b,a%b)为m,则m|b,m|(a-k*b),那么m|(a-k*b+k*b),即m|a。得证。
所以代码如下:
1 int gcd(int a,int b)
2 {
3 if(a%b==0)return b;
4 return gcd(b,a%b);
5 }
三:最小公倍数lcm
int lcm(int a,int b)
{
return a*b/gcd(a,b);
}