传送门

以此题题解纪念我第一道独立思考出的数论题$QwQ$。

首先质数肯定是要筛的。

考虑对于某一个质数$p$,满足$gcd(i,j)=p$的$(i,j)$有多少对:

显然$p|i$且 $p|j$,则设$i=ap$,$j=bp$。

即$gcd(ap,bp)=p$

把$p$提出来:$gcd(a,b)*p=p$

约去$p$:$gcd(a,b)=1$,也就是$a$、$b$互质

假设$a>b$,问题就变成了求$a$所有取值的欧拉函数的和。$ap$不能超过$n$,则$1\le a\le \left\lfloor\dfrac{n}{p}\right\rfloor$。直接预处理出欧拉函数和前缀和。其中$a,b$可互换,答案乘$2$。当$a=1,b=1$时互换是同一种情况,答案减去$cnt$($cnt$为质数个数)。

综上,$ans=\left(\sum\limits_{i=1}^{cnt}\sum\limits_{j=1}^{\left\lfloor\frac{n}{prime[i]}\right\rfloor}\varphi(j)\right)-cnt$

用的欧拉筛,时间复杂度$O(n)$。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>

#define maxn 10000005
#define inf 0x3f3f3f3f

using namespace std;

inline int read(){
    int x=0,y=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return y?-x:x;
}
long long sum[maxn],ans;
int phi[maxn],prime[maxn>>2],cnt;
bool is[maxn];
int main(){
    int n=read();
    sum[1]=phi[1]=1;
    for(register int i=2;i<=n;++i){
        if(!is[i])prime[++cnt]=i,phi[i]=i-1;
        sum[i]=sum[i-1]+(long long)phi[i];
        for(register int j=1;j<=cnt&&prime[j]*i<=n;++j){
            is[prime[j]*i]=1;
            if(i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }    
    for(register int i=1;i<=cnt;++i)
        ans+=sum[n/prime[i]];
    printf("%lld\n",ans*2-(long long)cnt);
}