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=1∑Ngcd(i,N)可知f(n)是积性函数(此处不给出证明)
不妨令N的素因子分解式N=p1a1p_{1}^{a_{1}}p1a1·p2a2p_{2}^{a_{2}}p2a2·…·pnanp_{n}^{a_{n}}pnan(pip_{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=1∑p1a1gcd(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}·kp1⋅k且k与p1p_{1}p1互素,故k可以取[1,p1a1−1p_{1}^{a_{1}-1}p1a1−1]中与p1p_{1}p1互素的数,而与p1a1−1p_{1}^{a_{1}-1}p1a1−1不互素的数均为p1p_{1}p1的倍数,所以满足条件的k有φ\varphiφ(p1a1−1p_{1}^{a_{1}-1}p1a1−1)个,即和p1a1p_{1}^{a_{1}}p1a1的最大公因数为p1p_{1}p1的数有φ\varphiφ(p1a1−1p_{1}^{a_{1}-1}p1a1−1)个;
依此类推……
和p1a1p_{1}^{a_{1}}p1a1的最大公因数为p1a1−1p_{1}^{a_{1}-1}p1a1−1的数有φ(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⋅φ(p1a1−1)+…+p1a1−1⋅φ(p1)+p1a1⋅φ(1)
由欧拉函数公式φ(x)=x∏i=1n(1−1pi)\varphi(x)=x\displaystyle\prod_{i=1}^{n}(1-\frac{1}{p_{i}})φ(x)=xi=1∏n(1−pi1)
(其中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)=a1⋅p1a1⋅(1−p11)+p1a1
=p1a1[a1(1−1p1)+1]=p_{1}^{a_{1}}[a_{1}(1-\frac{1}{p_{1}})+1]=p1a1[a1(1−p11)+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(1−p11)]⋅…⋅[1+an(1−pn1)]
=N∑i=1n(1+ai(1−1pi))N\displaystyle\sum_{i=1}^{n}(1+a_{i}(1-\frac{1}{p_{i}}))Ni=1∑n(1+ai(1−pi1))
解题代码如下,代码中为最大程度减少循环次数,还运用了定理:对任意正整数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;
}