1、试除法求约数
朴素想法是直接枚举1-n,如果n%i==0,i就是约数
但是考虑到约数是成对出现的,假设i是n的约数,那么n/i也是n的约数,所以只需要枚举到sqrt(n)即可
时间复杂度为:sqrt(n),需要证明排序的复杂度小于求约数的复杂度
排序复杂度是nlogn,那么我们就得知道n有多少个约数,但是对于不同的数的约数个数是不同的,所以我们只能估计
我们先求出1---n中约数的个数,然后除以n就是平均每个数的约数的个数
然后因为a是b的约数,那么b就是a的倍数,所以1---n中约数的个数等于倍数的个数
而1的倍数有n个,2的倍数有n/2个.....因此1---n中约数的个数为n(1+1/2+1/3+1/4+....)=nln n
所以平均每个数有ln n约等于log n个倍数。
排序复杂度为logn*log log n ,小于sqrt(n)
1 void get_divisors(int n){ 2 res.clear(); 3 for(int i=1;i<=n/i;i++){ 4 if(n%i==0){ 5 res.push_back(i); 6 if(n/i>i){ 7 res.push_back(n/i); 8 } 9 } 10 } 11 sort(res.begin(),res.end()); 12 }
2、约数个数和约数之和
这俩是基于唯一分解定理来的
每一个数大于一的数 x 都可以被分解为 x=p1^a1+p2^a2+....pk^ak的形式
所以对于一个数n,他的约数个数就为(a1+1)(a2+1)....(ak+1)
他的约数之和就为(p1^0+p1^1+...+p1^a1)(p2^0+p2^1+...+p2^a2)....(pk^0+pk^1+...+pk^ak)
约数个数(给定n个数,求这些数的乘积的约数个数)
1 #include<iostream> 2 #include<unordered_map> 3 using namespace std; 4 const int mod=1e9+7; 5 6 int main(void){ 7 int n; 8 unordered_map<int,int> mp; 9 cin>>n; 10 for(int i=0;i<n;i++){ 11 int a; 12 cin>>a; 13 for(int j=2;j<=a/j;j++){ 14 while(a%j==0){ 15 mp[j]++; 16 a/=j; 17 } 18 } 19 if(a>1){ 20 mp[a]++; 21 } 22 } 23 long long res=1; 24 for(auto it:mp){ 25 res=res*(it.second+1); 26 res%=mod; 27 } 28 cout<<res; 29 return 0; 30 }
约数之和
1 #include<iostream> 2 #include<unordered_map> 3 using namespace std; 4 const int mod=1e9+7; 5 int main(void){ 6 int n; 7 unordered_map<int,int> mp; 8 cin>>n; 9 for(int i=0;i<n;i++){ 10 int a; 11 cin>>a; 12 for(int j=2;j<=a/j;j++){ 13 while(a%j==0){ 14 a/=j; 15 mp[j]++; 16 } 17 } 18 if(a>1){ 19 mp[a]++; 20 } 21 } 22 23 long long res=1; 24 for(auto it:mp){ 25 long long t=1,prime=it.first,cnt=it.second; 26 while(cnt--){ 27 t=t*prime+1; 28 t%=mod; 29 } 30 res=res*t; 31 res%=mod; 32 } 33 cout<<res; 34 return 0; 35 }
3、最大公约数
辗转相除法,gcd(a,b)=gcd(b,a%b)
(规定0可以整除任何数)
证明:数学基本性质d|a,d|b---->d|xa+by,可由唯一分解定理证得
左--->右:
假设d|a,d|b,因为a%b=a-c*b,所以d|a-c*b,所以如果是a和b的约数,也一定是b和a%b的约数
右--->左:
假设d|b,d|a%b,所以d|a-c*b,又因为d|b,所以d|a-c*b+c*b--->d|a,所以d|a&&d|b
正确性得证。
1 #include<iostream> 2 using namespace std; 3 int gcd(int a,int b){ 4 return b?gcd(b,a%b):a; 5 } 6 int main(void){ 7 int n; 8 cin>>n; 9 for(int i=0;i<n;i++){ 10 int a,b; 11 cin>>a>>b; 12 cout<<gcd(a,b)<<endl; 13 } 14 return 0; 15 }