题目:51nod1188.
题目大意:给定一个数
n
n
n,求:
∑
i
=
1
n
∑
j
=
i
+
1
n
g
c
d
(
i
,
j
)
\sum_{i=1}^{n}\sum_{j=i+1}^{n}gcd(i,j)
i=1∑nj=i+1∑ngcd(i,j)
1 ≤ n ≤ 5 ∗ 1 0 6 1\leq n\leq 5*10^6 1≤n≤5∗106,数据组数 ≤ 5 ∗ 1 0 4 \leq 5*10^4 ≤5∗104.
直接推导下去:
∑
i
=
1
n
∑
j
=
i
+
1
n
g
c
d
(
i
,
j
)
=
∑
i
=
1
n
∑
j
=
1
i
g
c
d
(
i
,
j
)
−
∑
i
=
1
n
i
=
∑
i
=
1
n
∑
j
=
1
i
g
c
d
(
i
,
j
)
−
n
(
n
+
1
)
2
\sum_{i=1}^{n}\sum_{j=i+1}^{n}gcd(i,j)\\ =\sum_{i=1}^{n}\sum_{j=1}^{i}gcd(i,j)-\sum_{i=1}^{n}i\\ =\sum_{i=1}^{n}\sum_{j=1}^{i}gcd(i,j)-\frac{n(n+1)}{2}
i=1∑nj=i+1∑ngcd(i,j)=i=1∑nj=1∑igcd(i,j)−i=1∑ni=i=1∑nj=1∑igcd(i,j)−2n(n+1)
到这一步我们开始推导前半个式子:
∑
i
=
1
n
∑
j
=
1
i
g
c
d
(
i
,
j
)
=
∑
i
=
1
n
∑
k
=
1
i
k
∗
∑
j
=
1
i
[
g
c
d
(
i
,
j
)
=
k
]
\sum_{i=1}^{n}\sum_{j=1}^{i}gcd(i,j)\\ =\sum_{i=1}^{n}\sum_{k=1}^{i}k*\sum_{j=1}^{i}[gcd(i,j)=k]
i=1∑nj=1∑igcd(i,j)=i=1∑nk=1∑ik∗j=1∑i[gcd(i,j)=k]
设
m
=
i
k
m=\frac{i}{k}
m=ki,那么我们就可以把式子变为:
∑
i
=
1
n
∑
j
=
1
i
g
c
d
(
i
,
j
)
=
∑
i
=
1
n
∑
k
∣
i
k
∗
∑
j
=
1
m
[
g
c
d
(
j
,
m
)
=
1
]
=
∑
i
=
1
n
∑
k
∣
i
k
ϕ
(
m
)
\sum_{i=1}^{n}\sum_{j=1}^{i}gcd(i,j)\\ =\sum_{i=1}^{n}\sum_{k|i}k*\sum_{j=1}^{m}[gcd(j,m)=1]\\ =\sum_{i=1}^{n}\sum_{k|i}k\phi(m)
i=1∑nj=1∑igcd(i,j)=i=1∑nk∣i∑k∗j=1∑m[gcd(j,m)=1]=i=1∑nk∣i∑kϕ(m)
将
m
m
m代回式子中,即可得到:
∑
i
=
1
n
∑
j
=
1
i
g
c
d
(
i
,
j
)
=
∑
i
=
1
n
∑
k
∣
i
k
ϕ
(
i
k
)
\sum_{i=1}^{n}\sum_{j=1}^{i}gcd(i,j)=\sum_{i=1}^{n}\sum_{k|i}k\phi( \frac{i}{k})
i=1∑nj=1∑igcd(i,j)=i=1∑nk∣i∑kϕ(ki)
也就是说:
∑
i
=
1
n
∑
j
=
i
+
1
n
g
c
d
(
i
,
j
)
=
∑
i
=
1
n
∑
k
∣
i
k
ϕ
(
i
k
)
−
n
(
n
+
1
)
2
\sum_{i=1}^{n}\sum_{j=i+1}^{n}gcd(i,j)= \sum_{i=1}^{n}\sum_{k|i}k\phi(\frac{i}{k})-\frac{n(n+1)}{2}
i=1∑nj=i+1∑ngcd(i,j)=i=1∑nk∣i∑kϕ(ki)−2n(n+1)
仔细一思考,发现我们得到的式子大概是这样的:
∑
i
=
1
n
(
ε
×
ϕ
)
(
i
)
\sum_{i=1}^{n}(\varepsilon \times \phi)(i)
i=1∑n(ε×ϕ)(i)
这不就是两个积性函数的dirichlet卷积嘛,直接用dirichlet卷积预处理,然后前缀和一下就可以做到 O ( n log n + T ) O(n\log n+T) O(nlogn+T)解决这个问题.
但是我们知道两个积性函数的dirichlet卷积也是一个积性函数,而一般积性函数是可以用线性筛筛的,如果用线性筛预处理的话这道题就可以做到 O ( n + T ) O(n+T) O(n+T)解决了.
那么怎么线性筛呢?我们可以构造一个函数
f
f
f:
f
(
i
)
=
∑
k
∣
i
i
k
ϕ
(
k
)
f(i)=\sum_{k|i}\frac{i}{k}\phi(k)
f(i)=k∣i∑kiϕ(k)
考虑使用线性筛筛这个函数
f
f
f了:
1.当
i
i
i为素数时,
f
(
i
)
=
2
i
−
1
f(i)=2i-1
f(i)=2i−1.
2.当
g
c
d
(
i
,
p
r
[
j
]
)
=
1
gcd(i,pr[j])=1
gcd(i,pr[j])=1时,由于这个函数是积性函数,所以
f
(
i
∗
p
r
[
j
]
)
=
f
(
i
)
f
(
p
r
[
j
]
)
f(i*pr[j])=f(i)f(pr[j])
f(i∗pr[j])=f(i)f(pr[j]).
3.当
p
r
[
j
]
∣
i
pr[j]|i
pr[j]∣i时,那么:
f
(
i
∗
p
r
[
j
]
)
=
∑
k
∣
i
∗
p
r
[
j
]
i
∗
p
r
[
j
]
k
ϕ
(
k
)
f(i*pr[j])=\sum_{k|i*pr[j]}\frac{i*pr[j]}{k}\phi(k)
f(i∗pr[j])=k∣i∗pr[j]∑ki∗pr[j]ϕ(k)
我们设
m
u
l
[
i
]
mul[i]
mul[i]表示
i
i
i的所有最小素因子之积,那么:
f
(
i
∗
p
r
[
j
]
)
=
∑
k
∣
i
i
∗
p
r
[
j
]
k
ϕ
(
k
)
+
∑
k
∣
i
m
u
l
[
i
]
i
∗
p
r
[
j
]
k
∗
m
u
l
[
i
]
ϕ
(
k
∗
m
u
l
[
i
]
)
=
p
r
[
j
]
∗
f
(
i
)
+
∑
k
∣
i
m
u
l
[
i
]
i
∗
p
r
[
j
]
k
∗
m
u
l
[
i
]
ϕ
(
k
)
∗
ϕ
(
m
u
l
[
i
]
)
=
p
r
[
j
]
∗
f
(
i
)
+
∑
k
∣
i
m
u
l
[
i
]
i
∗
p
r
[
j
]
k
∗
m
u
l
[
i
]
ϕ
(
k
)
∗
m
u
l
[
i
]
∗
p
r
[
j
]
−
1
p
r
[
j
]
=
p
r
[
j
]
∗
f
(
i
)
+
(
p
r
[
j
]
−
1
)
∑
k
∣
i
m
u
l
[
i
]
i
k
ϕ
(
k
)
=
p
r
[
j
]
∗
f
(
i
)
+
m
u
l
[
i
]
(
p
r
[
j
]
−
1
)
∑
k
∣
i
m
u
l
[
i
]
i
m
u
l
[
i
]
∗
k
ϕ
(
k
)
=
p
r
[
j
]
∗
f
(
i
)
+
m
u
l
[
i
]
(
p
r
[
j
]
−
1
)
f
(
i
m
u
l
[
i
]
)
f(i*pr[j])=\sum_{k|i}\frac{i*pr[j]}{k}\phi(k)+\sum_{k|\frac{i}{mul[i]}}\frac{i*pr[j]}{k*mul[i]}\phi(k*mul[i])\\ =pr[j]*f(i)+\sum_{k|\frac{i}{mul[i]}}\frac{i*pr[j]}{k*mul[i]}\phi(k)*\phi(mul[i])\\ =pr[j]*f(i)+\sum_{k|\frac{i}{mul[i]}}\frac{i*pr[j]}{k*mul[i]}\phi(k)*mul[i]*\frac{pr[j]-1}{pr[j]}\\ =pr[j]*f(i)+(pr[j]-1)\sum_{k|\frac{i}{mul[i]}}\frac{i}{k}\phi(k)\\ =pr[j]*f(i)+mul[i](pr[j]-1)\sum_{k|\frac{i}{mul[i]}}\frac{i}{mul[i]*k}\phi(k)\\ =pr[j]*f(i)+mul[i](pr[j]-1)f(\frac{i}{mul[i]})
f(i∗pr[j])=k∣i∑ki∗pr[j]ϕ(k)+k∣mul[i]i∑k∗mul[i]i∗pr[j]ϕ(k∗mul[i])=pr[j]∗f(i)+k∣mul[i]i∑k∗mul[i]i∗pr[j]ϕ(k)∗ϕ(mul[i])=pr[j]∗f(i)+k∣mul[i]i∑k∗mul[i]i∗pr[j]ϕ(k)∗mul[i]∗pr[j]pr[j]−1=pr[j]∗f(i)+(pr[j]−1)k∣mul[i]i∑kiϕ(k)=pr[j]∗f(i)+mul[i](pr[j]−1)k∣mul[i]i∑mul[i]∗kiϕ(k)=pr[j]∗f(i)+mul[i](pr[j]−1)f(mul[i]i)
很明显 m u l [ i ] mul[i] mul[i]是可以在线性筛的时候顺便筛出来的,所以我们就可以愉快的 O ( n + T ) O(n+T) O(n+T)AC这道题啦.
线性筛代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=5000000;
int pr[N+9],b[N+9],tp;
LL mul[N+9],f[N+9],phi[N+9],F[N+9];
void sieve(int n){
for (int i=2;i<=n;++i) b[i]=1;
mul[1]=1;f[1]=1;phi[1]=1;
int v;
for (int i=2;i<=n;++i){
if (b[i]){
pr[++tp]=i;
phi[i]=LL(i-1);
mul[i]=LL(i);
f[i]=LL(2*i-1);
}
for (int j=1;j<=tp&&i*pr[j]<=n;++j){
b[v=i*pr[j]]=0;
if (i%pr[j]==0){
mul[v]=mul[i]*pr[j];
phi[v]=phi[i]*pr[j];
f[v]=f[i]*pr[j]+mul[i]*LL(pr[j]-1)*f[LL(i)/mul[i]];
break;
}
mul[v]=LL(pr[j]);
phi[v]=phi[i]*phi[pr[j]];
f[v]=f[i]*f[pr[j]];
}
}
for (int i=1;i<=n;++i)
F[i]=f[i]+F[i-1];
}
Abigail work(){
sieve(N);
}
Abigail getans(){
int T,n;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
printf("%lld\n",F[n]-LL(n)*LL(n+1)/2LL);
}
}
int main(){
work();
getans();
return 0;
}
emmm…顺便也写了一个dirichlet卷积的代码,如果实在看不懂线性筛做法的就参考dirichlet卷积的代码吧:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=5000000;
int pr[N+9],b[N+9],tp;
LL phi[N+9],F[N+9];
void sieve(int n){
for (int i=2;i<=n;++i) b[i]=1;
phi[1]=1;
for (int i=2;i<=n;++i){
if (b[i]) pr[++tp]=i,phi[i]=LL(i-1);
for (int j=1;j<=tp&&pr[j]*i<=n;++j){
b[i*pr[j]]=0;
if (i%pr[j]) phi[i*pr[j]]=phi[i]*phi[pr[j]];
else {phi[i*pr[j]]=phi[i]*pr[j];break;}
}
}
}
void dirichlet(int n){
for (int i=1;i<=n;++i)
for (int j=1;i*j<=n;++j)
F[i*j]+=phi[i]*j;
for (int i=1;i<=n;++i)
F[i]+=F[i-1];
}
Abigail work(){
sieve(N);
dirichlet(N);
}
Abigail getans(){
int T,n;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
printf("%lld\n",F[n]-LL(n)*LL(n+1)/2LL);
}
}
int main(){
work();
getans();
return 0;
}
貌似也有一个除法分块的做法可以做到 O ( n + T n ) O(n+T\sqrt{n}) O(n+Tn),比较慢但是好推一些,原理与上面的式子其实也差不多,这里就不写了.