入口
题意:给定正整数
n
n
n,求
1
≤
x
≤
y
1 \leq x \leq y
1≤x≤y 且
gcd
(
x
,
y
)
\gcd(x,y)
gcd(x,y)为素数的数对
(
x
,
y
)
(x,y)
(x,y) 有多少对。
idea:考虑每一个质数 P 对答案的贡献,设
x
≥
y
x \geq y
x≥y如果
g
c
d
(
x
,
y
)
=
p
gcd(x,y) = p
gcd(x,y)=p,那么就有
g
c
d
(
x
p
,
y
p
)
=
1
gcd( \frac{x}{p} ,\frac{y}{p} ) = 1
gcd(px,py)=1,对于每一个
x
p
\frac{x}{p}
px,贡献就是求小于等于它的数中与它互质的数的个数,这不就是欧拉函数的事情了嘛!
显然有
x
p
≤
n
p
\frac{x}{p} \leq \frac{n}{p}
px≤pn,那么就是求每一个小于等于
n
p
\frac{n}{p}
pn的 x 的
ϕ
(
x
)
\phi(x)
ϕ(x) 之和.对每一个质数 P 都要求一次,可以用前缀和优化,复杂度
O
(
n
)
O(n)
O(n)
注意此时是 x ≥ y x \geq y x≥y 的情况,要把答案乘2后减去 x = y x=y x=y 的情况
#include<bits/stdc++.h>
#define LL long long
#define N 10000007
using namespace std;
LL n,pr[N],phi[N],tot = 0,sum[N],ans = 0;
bool pd[N];
void get_phi()//线性筛欧拉函数
{
memset( pd,false,sizeof(pd) );
pd[ 1 ] = true;
phi[1] = 1;
for(int i=2;i<=10000000;i++)
{
if( !pd[i] )
{
tot++;
pr[ tot ] = i;
phi[i] = (i-1);
}
for(int j=1;j<=tot&&i*pr[j]<=10000000;j++)
{
pd[ i*pr[j] ] = true;
if( i%pr[j]==0 )
{
phi[ i*pr[j] ] = phi[i] * pr[j];
break;
}
phi[ i*pr[j] ] = phi[i] * (pr[j]-1);
}
}
}
void solve()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++) sum[i] = sum[i-1] + phi[i];
for(int j=1;j<=tot&&pr[j]<=n;j++)
{
ans += ( sum[ n/pr[j] ]*2 - 1 );
}
cout<<ans;
}
int main()
{
get_phi();
solve();
return 0;
}