约数之和
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 *… * 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);
}
以上是关于约数之和的主要内容,如果未能解决你的问题,请参考以下文章