题目
描述
给定整数
n
n
n,求
1
≤
x
,
y
≤
n
1 \leq x,y \leq n
1≤x,y≤n且
G
c
d
(
x
,
y
)
Gcd(x,y)
Gcd(x,y)为素数的数对
(
x
,
y
)
(x,y)
(x,y)有多少对?
输入
一个整数,
1
≤
n
≤
1
e
7
1\leq n \leq1e7
1≤n≤1e7
输出
一个整数
样例输入
4
样例输出
4
样例解释
(2,2),(2,4),(3,3),(4,2)
思路
我们记
β
(
a
)
\beta(a)
β(a)表示小于
a
a
a且与
a
a
a互质的某一个数
我们设
g
c
d
(
x
,
y
)
=
d
gcd(x,y)=d
gcd(x,y)=d,那么
g
c
d
(
⌊
x
d
⌋
,
⌊
y
d
⌋
)
=
1
gcd(\left \lfloor \frac{x}{d} \right \rfloor,\left \lfloor \frac{y}{d} \right \rfloor)=1
gcd(⌊dx⌋,⌊dy⌋)=1,而
⌊
x
d
⌋
<
⌊
y
d
⌋
\left \lfloor \frac{x}{d} \right \rfloor < \left \lfloor \frac{y}{d} \right \rfloor
⌊dx⌋<⌊dy⌋,那不就是求
φ
(
⌊
y
d
⌋
)
\varphi(\left \lfloor \frac{y}{d} \right \rfloor)
φ(⌊dy⌋)吗?
而
d
d
d是小于
n
n
n的素数,所以我们要把
n
n
n以内的所有素数都筛出来,而此时我们就可以
φ
(
i
)
\varphi(i)
φ(i)给做出来了。
而我们再想,既然
(
⌊
y
d
⌋
∗
d
,
β
(
⌊
y
d
⌋
)
∗
d
)
(\left \lfloor \frac{y}{d} \right \rfloor*d,\beta(\left \lfloor \frac{y}{d} \right \rfloor)*d)
(⌊dy⌋∗d,β(⌊dy⌋)∗d)是一个满足题意的数对,那么对于
i
,
1
≤
i
≤
⌊
y
d
⌋
i,1\leq i \leq \left \lfloor \frac{y}{d} \right \rfloor
i,1≤i≤⌊dy⌋
(
i
∗
d
,
β
(
i
)
∗
d
)
(i*d,\beta(i)*d)
(i∗d,β(i)∗d)是不是也是一个满足题意的数对
所以,对于每一个
d
d
d,我们都要求
1
≤
i
≤
⌊
n
d
⌋
1\leq i \leq \left \lfloor \frac{n}{d} \right \rfloor
1≤i≤⌊dn⌋的
φ
(
i
)
\varphi(i)
φ(i)之和即
∑
i
=
1
⌊
n
d
⌋
φ
(
i
)
\sum _{i=1} ^{\left \lfloor \frac{n}{d} \right \rfloor} \varphi(i)
i=1∑⌊dn⌋φ(i)
而最后的答案就可以表示成这样
∑
i
=
1
c
n
t
∑
j
=
1
⌊
n
d
i
⌋
φ
(
j
)
\sum _{i=1} ^{cnt} \sum _{j=1} ^{\left \lfloor \frac{n}{d_i} \right \rfloor} \varphi(j)
i=1∑cntj=1∑⌊din⌋φ(j)
对于
∑
i
=
1
⌊
n
d
⌋
φ
(
i
)
\sum _{i=1} ^{\left \lfloor \frac{n}{d} \right \rfloor} \varphi(i)
i=1∑⌊dn⌋φ(i)我们可以用前缀和优化一下,根据样例解释,两个不同的数调换位置也算一组数,所以最后要乘二,然而,素数不乘二,因此要减去
n
n
n以内素数的数量
代码如下
#include <cstdio>
#include <iostream>
using namespace std;
#define M 10000005
#define LL long long
int p[M];
LL n, ans, cnt;
LL phi[M];
bool v[M];
void sieve(int x){
phi[1] = 1;
for(int i = 2; i <= x; i ++){
if( !v[i] ){
p[++cnt] = i;
v[i] = 1;
phi[i] = i-1;
}
for(int j = 1; j <= cnt && i*p[j] <= x; j ++){
v[i*p[j]] = 1;
if( i % p[j] == 0 ){
phi[i*p[j]] = phi[i]*p[j];
break;
}
else phi[i*p[j]] = phi[i]*(p[j]-1);
}
}
for(int i = 1; i <= n; i ++)
phi[i] += phi[i-1];
}
int main(){
//freopen("gcd.in","r",stdin);
//freopen("gcd.out","w",stdout);
scanf("%lld", &n);
sieve(n);
for(int i = cnt; i > 0; i --)
ans = ans+phi[n/p[i]]*2;
printf("%lld\n", ans-cnt);
return 0;
}