约数之和

Posted hxss

tags:

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

题目描述

假设现在有两个自然数 A 和 B,S是 A^B的所有约数之和。
请你求出 S mod 9901 的值是多少。

输入格式

在一行中输入用空格隔开的两个整数 A 和 B。

输出格式

输出一个整数,代表 S mod 9901 的值。

数据范围

0≤A,B≤5×10^7

输入样例

2 3

输出样例

15

注意: A 和 B 不会同时为 0。

题目分析

由于A的约数之和为

则A^B的约数之和即为

而由于本题B的范围较大,故求解每一项的时候不能直接通过循环求解,故考虑下述方法

这样就可以实现约数之和的计算

代码实现

#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
#define int long long
const int mod=9901;
unordered_map<int,int>mp;
int quick(int a,int b)
	int res=1;
	while(b)
		if(b&1)res=res*a%mod;
		a=a*a%mod;
		b>>=1;
	
	return res;

int sum(int p,int k)
	if(k==1)return 1;
	if(k%2==0)return (quick(p,k/2)+1)*sum(p,k/2)%mod;
	else return (quick(p,k-1)+sum(p,k-1))%mod;

signed main()
	int a,b;
	cin>>a>>b;
	if(a==0)cout<<"0"<<endl;
	else
		//求因子
		for(int i=2;i<=a/i;i++)
			while(a%i==0)
				mp[i]++;
				a/=i;	
			
		
		if(a>1)mp[a]++;
		//计算约数和
		int res=1;
		for(auto t:mp)
			int temp=(t.second*b+1);
			res=res*sum(t.first,temp)%mod;
		 
		cout<<res%mod<<endl;
	
	return 0;


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

求一个数的约数

时间复杂度: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);
}

以上是关于约数之和的主要内容,如果未能解决你的问题,请参考以下文章

19: 约数之和

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

ZZNU 正约数之和

97. 约数之和(分治)

51nod 1220 约数之和

约数之和