给出一个n,求1-n这n个数,同n的最大公约数的和。比如:n = 6
1,2,3,4,5,6 同6的最大公约数分别为1,2,3,2,1,6,加在一起 = 15
输入
1个数N(N <= 10^9)
输出
公约数之和
输入样例
6
输出样例
15
1、对于一个数,显然gcd(n,i)(1<=i<=n)的答案只能是n的因子,那么,假设gcd(n,i)=x,我们现在就要求出有多少个i使得gcd(n,i)=x。如果gcd(n,i)=x,那么n和i都是x的倍数,突出x,式子就变为gcd(n/x,i/x)=1,满足这个式子的i的个数,显然就是n/x的欧拉函数的值。所以,答案就是枚举n的因子i,再求出欧拉函数phi(n/i),那么i对答案贡献就是
i*phi(n/i)。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N =1e5+10;
int prime[N],cnt;
bool vis[N];
void get_prime()
{
cnt=0;
for(int i=2;i<=N-10;i++)
{
if(!vis[i])
{
prime[cnt++]=i;
}
for(int j=0;j<cnt&&i*prime[j]<=N-10;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
break;
}
}
}
ll Eular(ll x)
{
//cout<<"ww\n";
ll res=x;
for(int i=0;i<cnt&&prime[i]*prime[i]<=x;i++)
{
//cout<<"?\n";
if(x%prime[i]==0)
{
res=res/prime[i]*(prime[i]-1);
while(x%prime[i]==0)
{
x/=prime[i];
//cout<<"!\n";
}
}
}
if(x!=1)
res=res/x*(x-1);
return res;
}
int main(void)
{
get_prime();
int n;
ll ans=0;
scanf("%d",&n);
for(int i=1;i*i<=n;i++)
{
if(n%i==0)
{
ans+=i*Eular(n/i);
if(i*i!=n)
{
ans+=(n/i)*Eular(i);
}
}
}
printf("%lld\n",ans);
}
2、观察求出的式子d*phi(n/d)=f(n),可以发现它是一个狄利克雷卷积,并且两函数都是积性函数,我们就可以考虑唯一分解。首先,欧拉函数有一个性质便是phi(p^k)=p^k-p^k-1(p是质数),现在我们求一下
f(p^k)=p^0*phi(p^k)+p^1*phi(p^(k-1))+...+p^k*phi(1),化简得f(p^k)=(k*p+p-k)*p^(k-1) ,那么对于要求得f(n),我们就可以把n唯一分解为n=(p1^k1)*(p2^k2)*...*(pm^km),答案就是f(n)=f(p1^k1)*f(p2^k2)*...*f(pm^km)。
(关于狄利克雷卷积:百度链接https://baike.baidu.com/item/%E7%8B%84%E5%88%A9%E5%85%8B%E9%9B%B7%E4%B9%98%E7%A7%AF/18903903?fr=aladdin)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#define ll long long
using namespace std;
const int N =1e5+10;
int prime[N];
bool vis[N];
int d[50],ex[50];
int cnt,cnt1;
void get_prime()
{
for(int i=2;i<=N-10;i++)
{
if(!vis[i]) prime[cnt++]=i;
for(int j=0;j<cnt&&i*prime[j]<=N-10;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
return ;
}
void Init()
{
cnt=cnt1=0;
get_prime();
return ;
}
void get_divisor(int n)
{
for(int i=0;i<cnt&&(ll)prime[i]*prime[i]<=n;i++)
{
if(n%prime[i]==0)
{
d[cnt1]=prime[i];
ex[cnt1]=0;
while(n%prime[i]==0)
{
ex[cnt1]++;
n/=prime[i];
}
cnt1++;
}
}
if(n>1)
{
d[cnt1]=n;
ex[cnt1++]=1;
}
return ;
}
ll poww(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1) res*=a;
a=a*a;
b>>=1;
}
return res;
}
int main(void)
{
Init();
int n;
ll ans=1;
scanf("%d",&n);
get_divisor(n);
for(int i=0;i<cnt1;i++)
{
ans*=(ex[i]*d[i]+d[i]-ex[i])*poww(d[i],ex[i]-1);
}
printf("%lld\n",ans);
return 0;
}