对于此题,我们有两种做法。
一:欧拉函数
题目可以转化为: 求gcd(x,y)==2 gcd(x,y)==3 gcd(x,y)==5 ... gcd(x,y)==prime 的对数之和
比如算gcd(x,y)==2的对数,这时y的取值只能是2,4,6,8...2*k
那么gcd(x,2)==2,gcd(x,4)==2,gcd(x,6)==2,gcd(x,8)==2 ... gcd(x,<=n中最大的且是2的倍数的数)==2的对数之和即为gcd(x,y)==2的对数
那么显然gcd(x,y)==2的答案为phi(1)+phi(2)+phi(3)+...phi(n/2)
同理可得gcd(x,y)==3的答案为phi(1)+phi(2)+phi(3)+...phi(n/3)
那么令sum(x)=phi(1)+phi(2)+phi(3)+...phi(x)
那么答案即为∑2*sum(n/prime[i])-1 (考虑(x,y) (y,x)为两种不同的答案和 (x,x) (x,x) 算同一种答案)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e7+1000;
int prime[N],phi[N],cnt,n;// prime:记录质数,phi记录欧拉函数
int Min_factor[N];// i的最小素因子
long long sum[N] ;
bool vis[N];
void Init()
{
cnt=0;
phi[1]=1;
int x;
for(int i=2;i<N;i++)
{
if(!vis[i])
{
prime[++cnt]=i;
phi[i]=i-1;
Min_factor[i]=i;
}
for(int k=1;k<=cnt&&prime[k]*i<N;k++)
{
x=prime[k]*i;
vis[x]=true;
Min_factor[x]=prime[k];
if(i%prime[k]==0)
{
phi[x]=phi[i]*prime[k];
break;
}
else phi[x]=phi[i]*(prime[k]-1);
}
}
}
int main()
{
Init();
for(int i=1;i<N;i++)sum[i]=sum[i-1]+phi[i];
//sort(prime,prime+cnt);
while(scanf("%d",&n)==1)
{
long long ans=0;
for(int i=1;prime[i]<=n;i++)
{
int k=n/prime[i];
ans+=sum[k]*2-1;
}
printf("%lld\n",ans);
}
}
二:莫比乌斯反演(懒得写题解了,直接把草稿放上来啦2333)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1e7+10;
LL prime[maxn],mu[maxn],sum[maxn];
bool vis[maxn];
void getmu(int n)
{
for(int i=0;i<=n;i++)mu[i]=sum[i]=0;
int tot=0;
mu[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i])
{
prime[++tot]=i;
mu[i]=-1;
sum[i]=1;
}
for(int j=1;prime[j]*i<=n;j++)
{
int x=prime[j]*i;
vis[x]=1;
if(i%prime[j]==0)
{
mu[x]=0;
sum=mu[i];
break;
}
else
{
mu[x]=-mu[i];
sum=mu[i]-sum[i];
}
}
}
for(int i=1;i<=n;i++)sum[i]+=sum[i-1];
}
int main()
{
int n;
while(scanf("%d",&n)==1)
{
getmu(n);
LL ans=0;
for(int i=1;i<=n;i++)
{
int nxt=n/(n/i);
ans+=(sum[nxt]-sum[i-1])*(n/i)*(n/i);
i=nxt;
}
printf("%lld\n",ans);
}
}