题解:
考虑每个质数
p
p
对答案的贡献,
相当于
a,b
a
,
b
互质,
gcd(x,y)
g
c
d
(
x
,
y
)
为
p
p
的数对个数即为中互质对
a,b
a
,
b
的个数。
令
a<=b
a
<=
b
,对于
b
b
,有
φ(b)
φ
(
b
)
个取值使
a,b
a
,
b
互质
所以符合条件的互质对
a,b
a
,
b
个数为
求一下前缀和就可以了。
关于欧拉函数是什么请自行百科。
那么 φ(n) φ ( n ) 怎么快速求?
考虑筛法:
若对于 i i ,已知所有的的 φ φ ,枚举的质数 p[j] p [ j ] ,可以求得 φ(x∗p[j]) φ ( x ∗ p [ j ] )
1、若 p[j] p [ j ] 与 x x 互质,
2、若不互质,设 x=t∗p[j]k x = t ∗ p [ j ] k
φ(x∗p[j])=φ(t∗p[j](k+1))=φ(t)∗φ(p[j](k+1)) φ ( x ∗ p [ j ] ) = φ ( t ∗ p [ j ] ( k + 1 ) ) = φ ( t ) ∗ φ ( p [ j ] ( k + 1 ) )
=φ(t)∗φ(p[j]k)∗p[j] = φ ( t ) ∗ φ ( p [ j ] k ) ∗ p [ j ]
=φ(x)∗p[j] = φ ( x ) ∗ p [ j ]
似乎过不了 107 10 7 的数据,那么怎么优化呢?
我们发现,很多数被重复计算了,比如
18=2∗9=3∗6 18 = 2 ∗ 9 = 3 ∗ 6
60=2∗30=3∗20=4∗15=5∗12=6∗10 60 = 2 ∗ 30 = 3 ∗ 20 = 4 ∗ 15 = 5 ∗ 12 = 6 ∗ 10
是否能让每个数只被算一次呢?
伪代码:
for i=2->n{
if i是质数{
φ(i)=i-1;
tot=tot+1;
p[tot]=i;
}
for j=1->tot{
p[j]*i标记为合数
计算φ(i*p[j])
if i%p[j]==0 break;//让每个数只被其最小质因子计算到
}
}
Code: C o d e :
#include<bits/stdc++.h>
#define ll long long
#define N 10000005
using namespace std;
int n,p,tot,phi[N],pri[N];
bool b[N];
ll ans,sum[N];
int main()
{
scanf("%d",&n);
phi[1]=1;
for(int i=2;i<=n;i++)
{
if(!b[i]){phi[i]=i-1;pri[++tot]=i;}
for(int j=1;j<=tot;j++)
{
int x=pri[j];
if(i*x>n)break;
b[i*x]=1;
if(i%x==0){phi[i*x]=phi[i]*x;break;}
else phi[i*x]=phi[i]*phi[x];
}
}
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+phi[i];
for(int i=1;i<=tot;i++)
ans+=sum[n/pri[i]]*2-1;
printf("%lld",ans);
return 0;
}