题解来自网上:
http://hzwer.com/3466.html
http://blog.csdn.net/xaphoenix/article/details/50677765
求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对
枚举每个素数,然后每个素数p对于答案的贡献就是(1 ~ n / p) 中有序互质对的个数
而求1~m中有序互质对x,y的个数,可以令y >= x, 当y = x时,有且只有y = x = 1互质,当y > x时,确定y以后符合条件的个数x就是phiy
所以有序互质对的个数为(1 ~ n/p)的欧拉函数之和乘2减1(要求的是有序互质对,乘2以后减去(1, 1)多算的一次)
那么就只需要先筛出欧拉函数再求个前缀和就可以了。
(我的模板貌似有点问题,通过my的改了改才过。我好菜QAQ...)
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<set>
#define LL long long
using namespace std;
int N,M,T;
const int NN = 11000000;
LL sum[NN];
int phi[NN],prime[NN/10],tot=0;
bool mark[NN]={0};
void getphi(){
phi[1]=1;
for(int i=2;i<=N;i++){
if(!mark[i]) {tot++;prime[tot]=i;phi[i]=i-1;}
for(int j=1;j<=tot;j++){
if(i*prime[j]>N) break;
mark[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];break;
}
else phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
}
int main()
{
scanf("%d",&N);
getphi();
sum[0]=0;
for(int i=1;i<=N;i++)
{
sum[i]=sum[i-1]+phi[i];
}
LL ans=0;
for(int i=1;i<=tot;i++)
{
ans+=sum[N/prime[i]];
}
ans=(ans-tot)*2+tot;
/*
或者借鉴这样写法 更好理解点:
for(int i=1;i<=tot;i++)
ans+=sum[n/pri[i]]*2-1;
*/
printf("%lld\n",ans);
return 0;
}