好久没做数学题了,看到这个题我顿时傻了。
题解
首先我们看到题目中我们要求的式子:(sum_{i=1}^{n}gcd(i,n))。
试想一下,如果有个 (i) 使得 (gcd(i,n)=d),那么这个 (i) 的贡献就是 (d),所以有多少个这样的 (i) 就会贡献出多少个 (d)。
(d) 一定是 (n) 的因子。
那怎么求有多少个这样的 (i) 呢?
我们将 (gcd(i,n)=d) 进一步化简: (gcd(frac{i}{d},frac{n}{d})=1)。
这一步转化之后,答案就很明显了:
我们要求有多少个 (i) 使得 (gcd(i,n)=d),可以转化为求有多少个 (frac{i}{d}) 使得 (gcd(frac{i}{d},frac{n}{d})=1),即求多少个数与 (frac{n}{d}) 互质。
这里引入欧拉函数。
欧拉函数
定义:在数论,对正整数 (n),欧拉函数是小于或等于 (n) 的正整数中与 (n) 互质的数的数目(因此 (φ(1)=1))。
通式:若 (n=p_1^{q_1}p_2^{q_2}p_3^{q_3}...p_k^{q_k}(p_1,p_2...p_k)均为质数()),则 (φ(n)=n*(1-frac{1}{p_1})*(1-frac{1}{p_2})*(1-frac{1}{p_3})...*(1-frac{1}{p_k}))。
若 (n) 为质数,则 (φ(n)=n-1)。
性质:
(①.)若 (m,n) 互质,则 (φ(m*n)=φ(m)*φ(n))。
(②.)若 (p) 是 (n) 的质因子,则 (φ(n*p)=p*φ(n))。
(③.)若 (n) 为奇质数,则 (φ(2n)=φ(n))。
代码实现:
我们将通式变形一下下:(φ(n)=n*frac{p_1-1}{p_1}*frac{p_2-1}{p_2}*frac{p_3-1}{p_3}...*frac{p_k-1}{p_k})。
我们可以枚举 (n) 的每个质因子 (p_i),然后将答案乘 (frac{p_i-1}{p_i}),然后再把 (n) 中的质因子 (p_i) 全部除掉。
ll phi(ll x) //求φ(n)
{
ll cnt=x;
for(ll i=2;i*i<=x;i++) //枚举x的质因子
{
if(x%i==0) //由于每个合数也可以由质数表示,所以i只能是质因子
{
cnt=cnt/i*(i-1); //统计答案
while(x%i==0) x/=i; //将x中的i全部除掉,这样才能保证枚举到全是质因子
}
}
if(x>1) cnt=cnt/x*(x-1); //如果x>1,说明还有个质因子没有统计到,我们在这里将其统计上
return cnt;
}
回到题目
介绍完欧拉函数,本题的解法就出来了。
我们枚举 (n) 的因子 (d),然后求有多少个 (i) 的贡献是 (d),个数为 (φ(frac{n}{d})),那么总贡献就是 (sum_{d|n}d*φ(frac{n}{d}))。
(Code:)
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const int N=1005;
ll n,ans;
ll phi(ll x) //求φ(n)
{
ll cnt=x;
for(ll i=2;i*i<=x;i++) //枚举x的质因子
{
if(x%i==0) //由于每个合数也可以由质数表示,所以i只能是质因子
{
cnt=cnt/i*(i-1); //统计答案
while(x%i==0) x/=i; //将x中的i全部除掉,这样才能保证枚举到全是质因子
}
}
if(x>1) cnt=cnt/x*(x-1); //如果x>1,说明还有个质因子没有统计到,我们在这里将其统计上
return cnt;
}
int main()
{
scanf("%lld",&n);
for(ll i=1;i*i<=n;i++) //枚举n的因子
{
if(n%i==0)
{
ans+=phi(n/i)*i; //算贡献
if(i*i!=n) ans+=phi(i)*(n/i); //如果i是n的因子,那么n/i也是n的因子,我们再算上n/i的贡献
}
}
printf("%lld
",ans);
return 0;
}