约数个数定理 和 约数和定理

约数个数定理 在数的因子这一部分具有很大的作用. 在这里就附上代码实现.

把任意一个数展开成素数连乘.

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分解质因数可得
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;
}
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值