题目传送门
本题题意转化成为:
∑
i
=
1
n
∑
j
=
1
n
[
g
c
d
(
i
,
j
)
=
=
p
]
\displaystyle\sum_{i=1}^{n}\displaystyle\sum_{j=1}^{n}[ gcd(i,j)==p]
i=1∑nj=1∑n[gcd(i,j)==p]
又因为
g
c
d
(
i
,
j
)
=
p
gcd(i,j)=p
gcd(i,j)=p转化成为
g
c
d
(
x
∗
p
,
y
∗
p
)
=
p
gcd(x*p,y*p)=p
gcd(x∗p,y∗p)=p 那么等价于
g
c
d
(
x
,
y
)
=
1
gcd(x,y)=1
gcd(x,y)=1
那么
1
<
=
x
,
y
<
=
n
/
p
1<=x,y<=n/p
1<=x,y<=n/p
至此,问题转化成为了请您找出
1
<
=
x
,
y
<
=
n
/
p
1<=x,y<=n/p
1<=x,y<=n/p,同时
x
,
y
x,y
x,y又满足互质的
x
,
y
x,y
x,y的对数。
又因为欧拉函数
ϕ
(
n
)
\phi(n)
ϕ(n)就是小于
n
n
n的和
n
n
n互质的数的个数。
至此答案就显而易见了
∑
1
n
/
p
,
1
<
=
x
,
y
<
=
n
g
c
d
(
x
,
y
)
=
1
\displaystyle\sum_{1}^{n/p,1<=x,y<=n}gcd(x,y)=1
1∑n/p,1<=x,y<=ngcd(x,y)=1
#include<iostream>
using namespace std;
typedef long long ll;
const ll N=1e7+10;
ll primes[N], cnt; // primes[]存储所有素数
ll euler[N]; // 存储每个数的欧拉函数
bool st[N]; // st[x]存储x是否被筛掉
void get_eulers(ll n)
{
euler[1] = 1;
for (ll i = 2; i <= n; i ++ )
{
if (!st[i])
{
primes[cnt ++ ] = i;
euler[i] = i - 1;
}
for (ll j = 0; primes[j] <= n / i; j ++ )
{
ll t = primes[j] * i;
st[t] = true;
if (i % primes[j] == 0)
{
euler[t] = euler[i] * primes[j];
break;
}
euler[t] = euler[i] * (primes[j] - 1);
}
}
cout<<euler[1]<<" "<<euler[2]<<" "<<euler[3]<<endl;
for(ll i=1;i<=n;i++)euler[i]+=euler[i-1];
}
int main(){
get_eulers(N);
ll n,ans=0;
cin>>n;
for(ll i=0;i<cnt&&primes[i]<=n;++i){
ans+=2*euler[n/primes[i]]-1;
//为什么减去1?因为(1,1)这个情况算了两次
}
//cout<<primes[2]<<endl;
cout<<ans<<endl;
}