约数(试除法求约数,约数之和,约数之差,欧几里得算法)

Posted 一只特立独行的猫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了约数(试除法求约数,约数之和,约数之差,欧几里得算法)相关的知识,希望对你有一定的参考价值。

求一个数的约数

时间复杂度:O(sqrt(n))
空间复杂度:O(1)
思路:
通过a|n可得(n/a)|n。枚举[1,sqrt(n)]的每一个整数,来判断n是否可以被整除。
代码:

#include<iostream>

using namespace std;

void solve(int n){
	for(int i=1;i<=n/i;i++){
		if(n%i==0){
			cout<<i<<" "<<n/i<<" ";
		}
	}
	cout<<endl;
}

int main(){
	int n;
	cin>>n;
	solve(n);
	return 0;
}

约数个数

时间复杂度:O(sqrt(n))
空间复杂度:O(log(n))
思路:
求一个数的约数个数,有如下公式:

对n进行分解质因数:
n = p1a1 * p2a2 *… * pnan
又排列组合可知,ai处元素的可能取值为[0,ai],所以共有以下情况:
res = (a1+1)*(a2+1)*…*(an+1)

根据上述公式,可以得到以下代码

分解质因数的O(sqrt(n))的解法的详细解释可以看这篇博客:
https://blog.csdn.net/qq_45931661/article/details/119719561

代码:

#include<iostream>
#include<unordered_map>

using namespace std;

typedef long long ll;

const int mod = 1e9 + 7;

unordered_map<int, int > prime;

void solve(int n) {
	//对n分解质因数
	for (int i = 2; i <= n / i; i++) {
		while (n % i == 0) {
			n /= i;
			prime[i]++;
		}
	}
	if (n != 1) {
		//考虑比sqrt(n)大的唯一的一个数
		prime[n]++;
	}
}

int main() {
	int n;
	cin>>n;
	solve(n);
	ll res = 1;
	for (auto x : prime) {
		res = res * (x.second + 1)%mod;
	}
	cout << res << endl;
	return 0;
}

约数之和

时间复杂度:O(sqrt(n))
空间复杂度:O(log(n))
思路:
对一个数求约数的和,有如下公式:

对n进行分解质因数:
n = p1a1 * p2a2 *… * pnan

res= p10*p20*…*pn0+ p11*p21 *…*pn1+ …+ p1n * p2n *…*pnn
=(p10+p11+…+p1n)*(p20 +p21+…+p2n)*(pn0+pn1+…+pnn)

根据公式,可以得到如下代码:
代码:

#include<iostream>
#include<unordered_map>

using namespace std;

typedef long long ll;

const int mod = 1e9+7;

unordered_map<int,int > prime;

void solve(int x){
		//分解质因数
    for(int i=2;i<=x/i;i++){
        while(x%i==0){
            x/=i;
            prime[i]++;
        }
    }
    if(x!=1) prime[x]++;
}

int main(){
    int n;
    cin>>n;
    while(n--){
        int x;
        cin>>x;
        solve(x);
    }
    ll res=1;
    for(auto x: prime){
        ll a = x.first,b=x.second;
        ll temp=1;
        for(int i=0;i<b;i++){
            temp = (temp*a+1)%mod;//秦九昭算法求(p^n+p^(n-1)+...+p^0)
        }
        res = (res*temp)%mod;
    }
    cout<<res<<endl;
    return 0;
}

欧几里得算法

时间复杂度:O(log(a+b))
思路:
对任意两个正整数,有如下公式:

gcd(a,b)=gcd(b,a%b) (gcd是求最大公约数的意思)

证明:
由d|a和d|b可以推出:d|(xa+yb)也成立
由于a%b = a - ceil(a/b)*b(ceil是向下取整)
令a%b = a-c*b
1.d|a,d|b ----------》 d|b,d|(a-c*d)
2.d|b,d|a-c*d ----------》d|b,d|(a-c*d+c*d) ---------》d|b,d|a

由此,我们得到了d|a和d|b与d|b和d|(a%b)的公约数集合是等价的。

代码:

int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}

以上是关于约数(试除法求约数,约数之和,约数之差,欧几里得算法)的主要内容,如果未能解决你的问题,请参考以下文章

蓝桥杯冲击-02约数篇(必考)

869. 试除法求约数

AcWing 869. 试除法求约数(枚举)

Sumdiv|同余|约数|拓展欧几里得算法

蓝桥杯中常用的数学算法

蓝桥杯中常用的数学算法