在数论中有一个质因数分解定理,可利用其中的一些性质来求一个数的因子个数及其因子和,下面附上定理及代码。
下面是代码
#include<bits/stdc++.h>
using namespace std;
//求因子个数
int fun1(int x)
{
int len=sqrt(x);
int ans=1;
int cnt;
for(int i=2;i<=len;i++)
{
cnt=0;
while(x%i==0)
{
x/=i;cnt++;
}
ans*=(1+cnt);
}
if(x>1) ans*=2;//x>1说明还剩最后一个因子,所以要乘(1+1)
return ans;
}
//求因子和
int fun2(int x)
{
int len=sqrt(x);
int ans=1;
int cnt;
for(int i=2;i<=len;i++)
{
cnt=1;
while(x%i==0)
{
cnt*=i;
x/=i;
}
ans*=(cnt*i-1)/(i-1);
}
if(x>1) ans*=(x+1);同理剩下一个因子,且其指数为1,所以乘以(x^2-1)/(x-1)=(x+1)
return ans;
}
int main()
{
int n;
cin>>n;
printf("%d %d",fun1(n),fun2(n));
return 0;
}
下面给出一道相关例题:
Sumdiv
题意:
有两个自然数a和b(a,b≤50000000)
求a的b次方的所有约数之和模9901
输入格式:一行,包含由空格分隔的两个自然数a和b
输出格式:一行,a的b次方的约数和模9901
样例
输入: 2 3
输出:15
分析:容易想到我们需要先对a进行质因数分解,再对a的各个质因数的幂次乘以b即得a^b的质因数分解式,数据太大,所以我们必须要取模,我们容易发现等比数列求和公式中有分母,但是再模运算中不允许有除法的出现,所以我们必须求出分母相对于模值的逆元,用乘以逆元的方式来代替除法操作,但需注意的是,a关于b有逆元的充分条件是(a,b)=1,所以当分母与模值不互质时需要特殊处理一下,但我们需要注意到的是模值是一个质数,故当且仅当分母是模值的倍数时才不能求得相对应的乘法逆元,求逆元我们常用的操作是费马小定理即(a^(p-1),p)=1,条件是(a,p)=1,则a对应模值为p的逆元为a^(p-2),所以逆元我们可以用快速幂求得,下面是这道题的代码
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int mod=9901;
const int N=50003;
ll fact[N];
ll flag;
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
void init(ll a,ll b)//质因数分解
{
ll l=sqrt(a);
for(int i=2;i<=l;i++)
while(a%i==0)
{
fact[i]+=b;
a/=i;
}
if(a!=1) flag=a;
}
ll fun(ll a,ll b)//求出a^0+a^1+……+a^b
{
if((a-1)%mod==0) return (b+1);//特判不互质的情况
ll ans=(qpow(a,b+1)+mod-1)%mod;
ll infact=qpow(a-1,mod-2);//求逆元
return (ans*infact%mod);
}
int main()
{
ll a,b;
flag=0;
cin>>a>>b;
init(a,b);
ll ans=1;
int temp=sqrt(a);
for(int i=2;i<=temp;i++)
if(fact[i]) ans=ans*fun(i,fact[i])%mod;
if(flag) ans=ans*fun(flag,b)%mod;
printf("%lld",ans);
return 0;
}