POJ2480:求所有最大公因数之和(附带详细数学推导)

本文介绍了一种解决特定数学问题的算法,该问题是计算给定整数N范围内所有数与N的最大公约数之和。文章详细阐述了解决方案的推导过程,并给出了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Longge is good at mathematics and he likes to think about hard mathematical problems which will be solved by some graceful algorithms. Now a problem comes: Given an integer N(1 < N < 2^31),you are to calculate ∑gcd(i, N) 1<=i <=N.
“Oh, I know, I know!” Longge shouts! But do you know? Please solve it.


Input
Input contain several test case.
A number N per line.


Output
For each N, output ,∑gcd(i, N) 1<=i <=N, a line


Sample Input
2
6


Sample Output
3
15


推导(其中所用欧拉函数与积性函数知识可自行查阅):

设f(N)=∑i=1Ngcd(i,N)设f(N)=\displaystyle\sum_{i=1}^{N}{gcd_{(i,N)}}f(N)=i=1Ngcd(i,N)可知f(n)是积性函数(此处不给出证明)
不妨令N的素因子分解式N=p1a1p_{1}^{a_{1}}p1a1·p2a2p_{2}^{a_{2}}p2a2·…·pnanp_{n}^{a_{n}}pnanpip_{i}pi是素数)

所以由积性函数的性质可知
f(N)=f(p1a1)⋅f(p2a2)⋅…⋅f(pnan)f(N)=f(p_{1}^{a_{1}})·f(p_{2}^{a_{2}})·…·f(p_{n}^{a_{n}})f(N)=f(p1a1)f(p2a2)f(pnan)

对f(p1a1)=∑i=1p1a1gcd(i,p1a1)对f(p_{1}^{a_{1}})=\displaystyle\sum_{i=1}^{p_{1}^{a_{1}}}{gcd_{(i,p_{1}^{a_{1}})}}f(p1a1)=i=1p1a1gcd(i,p1a1)
p1a1p_{1}^{a_{1}}p1a1互素的数的个数有φ\varphiφ(p1a1p_{1}^{a_{1}}p1a1)个,他们的最大公因数是1;
p1a1p_{1}^{a_{1}}p1a1的最大公因数为p1p_{1}p1的数都可以写成p1⋅kp_{1}·kp1k且k与p1p_{1}p1互素,故k可以取[1,p1a1−1p_{1}^{a_{1}-1}p1a11]中与p1p_{1}p1互素的数,而与p1a1−1p_{1}^{a_{1}-1}p1a11不互素的数均为p1p_{1}p1的倍数,所以满足条件的k有φ\varphiφ(p1a1−1p_{1}^{a_{1}-1}p1a11)个,即和p1a1p_{1}^{a_{1}}p1a1的最大公因数为p1p_{1}p1的数有φ\varphiφ(p1a1−1p_{1}^{a_{1}-1}p1a11)个;
依此类推……
p1a1p_{1}^{a_{1}}p1a1的最大公因数为p1a1−1p_{1}^{a_{1}-1}p1a11的数有φ(p1)\varphi(p_{1})φ(p1)个。
p1a1p_{1}^{a_{1}}p1a1的最大公因数为p1a1p_{1}^{a_{1}}p1a1的数有φ\varphiφ(1)=1个。
将它们求和,即可得
f(p1a1)=1⋅φ(p1a1)+p1⋅φ(p1a1−1)+…+p1a1−1⋅φ(p1)+p1a1⋅φ(1)f(p_{1}^{a_{1}})=1·\varphi(p_{1}^{a_{1}})+p_{1}·\varphi(p_{1}^{a_{1}-1})+…+p_{1}^{a_{1}-1}·\varphi(p_{1})+p_{1}^{a_{1}}·\varphi(1)f(p1a1)=1φ(p1a1)+p1φ(p1a11)++p1a11φ(p1)+p1a1φ(1)

由欧拉函数公式φ(x)=x∏i=1n(1−1pi)\varphi(x)=x\displaystyle\prod_{i=1}^{n}(1-\frac{1}{p_{i}})φ(x)=xi=1n(1pi1)
(其中pip_{i}pi是x的所有质因数,x是不为0的整数)
所以f(p1a1)=a1⋅p1a1⋅(1−1p1)+p1a1f(p_{1}^{a_{1}})=a_{1}·p_{1}^{a_{1}}·(1-\frac{1}{p_{1}})+p_{1}^{a_{1}}f(p1a1)=a1p1a1(1p11)+p1a1
=p1a1[a1(1−1p1)+1]=p_{1}^{a_{1}}[a_{1}(1-\frac{1}{p_{1}})+1]=p1a1[a1(1p11)+1]

所以f(N)=f(p1a1)⋅f(p2a2)⋅…⋅f(pnan)f(N)=f(p_{1}^{a_{1}})·f(p_{2}^{a_{2}})·…·f(p_{n}^{a_{n}})f(N)=f(p1a1)f(p2a2)f(pnan)
=N⋅[1+a1(1−1p1)]⋅…⋅[1+an(1−1pn)]N·[1+a_{1}(1-\frac{1}{p_{1}})]·…·[1+a_{n}(1-\frac{1}{p_{n}})]N[1+a1(1p11)][1+an(1pn1)]
=N∑i=1n(1+ai(1−1pi))N\displaystyle\sum_{i=1}^{n}(1+a_{i}(1-\frac{1}{p_{i}}))Ni=1n(1+ai(1pi1))




解题代码如下,代码中为最大程度减少循环次数,还运用了定理:对任意正整数n,最多只有一个素因子大于n\sqrt{n}n,且如果有素因子大于n\sqrt{n}n,那么这个素因子的次数一定是1

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;

int main()
{
    int n;
    long long ans;
    while(cin>>n) {
        ans=n;
        int b=sqrt(1.0*n);//sqrt的形参是double类型的。
        for(int i=2; i<=b; i++)
        {
            if(n%i==0)//说明i是其中一个素因子
            {
                int a=0;
                while(n%i==0)//计算对应这个素因子的次数
                {
                    n/=i;
                    a++;
                }
                ans=ans+ans*a*(i-1)/i;//技巧:像此题除法一定要保证是整除
            }
        }
        if(n!=1)
            ans=ans+ans*(n-1)/n;//此处是在判断是否存在大于根号n的质因子
        cout<<ans<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值