约数(试除法求约数,约数之和,约数之差,欧几里得算法)
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 *… * pnanres= 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);
}
以上是关于约数(试除法求约数,约数之和,约数之差,欧几里得算法)的主要内容,如果未能解决你的问题,请参考以下文章