约数个数定理 在数的因子这一部分具有很大的作用. 在这里就附上代码实现.
把任意一个数展开成素数连乘.
void solve(ll n) //素数连乘
{
printf("%d=",n);
int flag = 0;
for(ll i=2;i*i<=n;i++){
while(n%i == 0){
n = n/i;
if(!flag) printf("%d",i);
else printf("*%d",i);
flag |= 1;
}
}
if(n!=1 && !flag) printf("%d\n",n);
else if(n!= 1 && flag) printf("*%d\n",n);
else printf("\n");
}
求一个数的正约数个数,从定理当中的关系就知道,就在上面的程序随便改改就行了(包括其本身)
ll getnum(ll n) //得到a的约数个数.
{
ll res=1;
for(ll i=2;i*i<=n;i++){
ll k=0;
while(n%i == 0){
n = n/i;
k++;
}
if(k) res *= (k+1);
}
if(n != 1) res=res*2;
if(res==1){
if(n==1) return 1;
else return 2;
}
return res;
}
求正约数应用例题hihocoder – 1284
//直接暴力肯定不行, 所以想到求他们的约数, 则n的约数*m的约数/GCD(n,m)的约数就是答案. 求约数用以上定理.
AC Code
/** @Cain*/
ll getnum(ll n) //得到a的约数个数.
{
ll res=1;
for(ll i=2;i*i<=n;i++){
ll k=0;
while(n%i == 0){
n = n/i;
k++;
}
if(k) res *= (k+1);
}
if(n != 1) res=res*2; //最后一个素数.
if(res==1){ //本身就是素数或1.
if(n==1) return 1;
else return 2;
}
return res;
}
void solve()
{
ll n,m;
scanf("%lld%lld",&n,&m);
ll k = __gcd(m,n);
ll num1 = getnum(n);
ll num2 = getnum(m);
ll num3 = getnum(k);
ll t = __gcd(num3,num1*num2);
printf("%lld %lld\n",1ll*num1*num2/t,1ll*num3/t);
}
对于一个大于1正整数n可以分解质因数:n=p1^a1*p2^a2*p3^a3*…*pk^ak,
则由约数个数定理可知n的正约数有(a₁+1)(a₂+1)(a₃+1)…(ak+1)个,
那么n的(a₁+1)(a₂+1)(a₃+1)…(ak+1)个正约数的和为
f(n)=(p1^0+p1^1+p1^2+…p1^a1)(p2^0+p2^1+p2^2+…p2^a2)…(pk^0+pk^1+pk^2+…pk^ak)
证明:若n可以分解质因数:n=p1^a1*p2^a2*p3^a3*…*pk^ak,
可知p1^a1的约数有:p1^0, p1^1, p1^2……p1^a1
同理可知,pk^ak的约数有:pk^0, pk^1, pk^2……pk^ak ;
实际上n的约数是在p1^a1、p2^a2、…、pk^ak每一个的约数中分别挑一个相乘得来,
可知共有(a₁+1)(a₂+1)(a₃+1)…(ak+1)种挑法,即约数的个数。
由乘法原理可知它们的和为
f(n)=(p1^0+p1^1+p1^2+…p1^a1)(p2^0+p2^1+p2^2+…p2^a2)…(pk^0+pk^1+pk^2+…pk^ak)
解:将360分解质因数可得
360=2^3*3^2*5^1
由约数和定理可知,360所有正约数的和为
(2^0+2^1+2^2+2^3)×(3^0+3^1+3^2)×(5^0+5^1)=(1+2+4+8)(1+3+9)(1+5)=15×13×6=1170
可知360的约数有1、2、3、4、5、6、8、9、10、12、15、18、
20、24、30、36、40、45、60、72、90、120、180、360;则它们的和为
1+2+3+4+5+6+8+9+10+12+15+18+20+24+30+36+40+45+60+72+90+120+180+360=1170
代码实现
ll qpow(ll x, ll y )
{
ll res = 1;
while(y){
if(y&1) res *= x;
x *= x;
y >>= 1 ;
}
return res;
}
ll getsum(ll n) //返回n的约数和是多少.
{
ll res=1;
for(ll i=2;i*i<=n;i++){
ll k=0;
while(n%i == 0){
n = n/i;
k++;
}
res *= ((1-qpow(i,k+1))/(1-i));
} //用等比数列公式(快速幂)算.
if(n != 1) res *= (1 + n);
return res;
}