给出一个n,求1-n这n个数,同n的最大公约数的和。比如:n = 6
1,2,3,4,5,6 同6的最大公约数分别为1,2,3,2,1,6,加在一起 = 15
Input
1个数N(N <= 10^9)
Output
公约数之和
Input示例
6
Output示例
15
思路:先转化成数学公式:
ans=∑i=1ngcd(i,n)ans=∑i=1ngcd(i,n)
肯定不能一一枚举转而去枚举数量较小的gcd:
ans=∑d|nd∗∑i=1ngcd(i,n)=d=∑d|nd∗∑i=1ndgcd(i,nd)=1ans=∑d|nd∗∑i=1ngcd(i,n)=d=∑d|nd∗∑i=1ndgcd(i,nd)=1
很显然,里面就是个欧拉函数所以就是:
ans=∑d|nd∗ϕ(nd)ans=∑d|nd∗ϕ(nd)
到这里我们有做法一:
就可以暴力一点去枚举这个dd就可以了,计算一下欧拉函数,也是可以ac的,这是
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ull unsigned long long
#define ll long long
#define ul unsigned int
#define maxn 40000
using namespace std;
bool isP[maxn];
int prime[maxn];
int cnt;
void init()
{
for(int i=2;i<maxn;i++)
{
if(!isP[i])prime[cnt++]=i;
for(int j=0;j<cnt&&(ll)i*prime[j]<maxn;j++)
{
isP[i*prime[j]]=true;
if(i%prime[j]==0)break;
}
}
}
int fac[30];
int e[30];
int k;
void getFac(int n)
{
k=0;
for(int i=0;(ll)prime[i]*prime[i]<=n;i++)
{
if(n%prime[i]==0)
{
fac[k]=prime[i];
e[k]=0;
while(n%prime[i]==0)
{
n/=prime[i];
e[k]++;
}
k++;
}
}
if(n>1){fac[k]=n;e[k++]=1;}
}
int phi(int x)
{
int ans=x;
for(int i=0;(ll)prime[i]*prime[i]<=x;i++)
{
if(x%prime[i]==0)
{
ans=ans/prime[i]*(prime[i]-1);
while(x%prime[i]==0)x/=prime[i];
}
}
if(x>1)ans=ans/x*(x-1);
return ans;
}
int n;
ll ans=0;
void dfs(int cur,int temp)
{
if(cur==k)
{
ans+=temp*phi(n/temp);
return;
}
dfs(cur+1,temp);
int now=temp;
for(int i=1;i<=e[cur];i++)
{
now*=fac[cur];
dfs(cur+1,now);
}
}
int main()
{
init();
cin>>n;
getFac(n);
dfs(0,1);
cout<<ans<<endl;
return 0;
}
做法二:
我们发现这个其实是一个狄利克雷卷积的形式,两个卷积函数显然是积性,所以卷积也是积性,我们设这个ansans为ff
我们来观察一下,p为质数,观察是否可以直接计算:
f(pk)=∑i=0kpiϕ(pk−i)f(pk)=∑i=0kpiϕ(pk−i)
发现前k向的值其实都是一样的,均为pk−pk−1pk−pk−1,最后一项为pkpk
所以
f(pk)=(k+1)pk−kpk−1f(pk)=(k+1)pk−kpk−1
; 那么现在就只要把一个数唯一分解掉,这题就做完了,
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ull unsigned long long
#define ll long long
#define ul unsigned int
#define maxn 40000
using namespace std;
bool isP[maxn];
int prime[maxn];
int cnt;
void init()
{
for(int i=2;i<maxn;i++)
{
if(!isP[i])prime[cnt++]=i;
for(int j=0;j<cnt&&(ll)i*prime[j]<maxn;j++)
{
isP[i*prime[j]]=true;
if(i%prime[j]==0)break;
}
}
}
int fac[30];
int e[30];
int k;
void getFac(int n)
{
k=0;
for(int i=0;(ll)prime[i]*prime[i]<=n;i++)
{
if(n%prime[i]==0)
{
fac[k]=prime[i];
e[k]=0;
while(n%prime[i]==0)
{
n/=prime[i];
e[k]++;
}
k++;
}
}
if(n>1){fac[k]=n;e[k++]=1;}
}
ll P(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)ans*=a;
b>>=1;
a*=a;
}
return ans;
}
int n;
ll solve()
{
ll ans=1;
for(int i=0;i<k;i++)
ans*=(e[i]+1)*P(fac[i],e[i])-e[i]*P(fac[i],e[i]-1);
return ans;
}
int main()
{
init();
cin>>n;
getFac(n);
cout<<solve()<<endl;
return 0;
}