标题党又来了
题目描述
给定 n n n,求 ∑ i = 1 n ∑ j = i + 1 n g c d ( i , j ) \sum\limits_{i=1}^{n} \sum\limits_{j=i+1}^{n}gcd(i,j) i=1∑nj=i+1∑ngcd(i,j)。
解法1:暴力
两个for
搞定。每一次计算复杂度为
O
(
n
2
)
O(n^2)
O(n2)。
于是你可以水掉UVA11417。
解法2:化柿子
既然直接枚举 i , j i,j i,j不行,那么我们换成枚举 g c d gcd gcd,假设我们已经确定了 i , j i,j i,j的 g c d gcd gcd为 k k k,那么 g c d ( i / k , j / k ) = 1 gcd(i/k,j/k)=1 gcd(i/k,j/k)=1,于是问题转化为,在 [ 1 , ⌊ n k ⌋ ] [1,\lfloor \frac{n}{k} \rfloor] [1,⌊kn⌋]范围内,互质的无序数对个数。
我们接着转化,假设我们已经知道了互质的数中的较大的一个 a a a,那么我们要做的就是求出小于这个数的与它互质的数。想到了什么?欧拉函数!!
于是我们会发现,我们要求的就是在 [ 1 , ⌊ n k ⌋ ] [1,\lfloor \frac{n}{k} \rfloor] [1,⌊kn⌋]范围内的所有数的欧拉函数值得和。
那么最终的答案就是
∑
k
=
1
n
∑
d
=
1
⌊
n
k
⌋
ϕ
(
d
)
\sum_{k=1}^{n} \sum_{d=1}^{\lfloor\frac{n}{k}\rfloor}\phi(d)
k=1∑nd=1∑⌊kn⌋ϕ(d)
然后我们发现,后面一个和可以通过线性筛和前缀和预处理做到
O
(
1
)
O(1)
O(1)查询和。于是成功的把每次计算复杂度降到了
O
(
n
)
O(n)
O(n)。
于是你可以*掉洛谷1390和洛谷2398,还有洛谷2568。
不过要注意的是,这些题中的 ϕ ( 1 ) \phi(1) ϕ(1)的初始值会有所不同,并且有些题求的是有序数对个数,需要对答案进行一些简单处理。
终极解法:统统预处理
尽管解法2已经将时间复杂度压到了一次计算
O
(
n
)
O(n)
O(n),几乎是最优了,但对于多组数据,尤其是几万甚至几十万的数据组数时,就显得太慢了愚蠢,垃圾。
我们发现, O ( n ) O(n) O(n)复杂度的瓶颈在于每次都需要枚举计算。那么我们考虑用预处理把所有的答案都预处理出来,做到 O ( 1 ) O(1) O(1)查询。
继续化柿子:
设
f
(
n
)
=
∑
i
=
1
n
−
1
g
c
d
(
i
,
n
)
那
么
a
n
s
=
∑
i
=
1
n
f
(
n
)
f
(
n
)
=
∑
d
∣
n
d
×
∑
i
=
1
n
−
1
[
g
c
d
(
i
,
n
)
=
d
]
=
∑
d
∣
n
d
×
∑
i
=
1
n
d
−
1
[
g
c
d
(
i
,
n
d
)
=
1
]
=
∑
d
∣
n
d
×
ϕ
(
n
d
)
\begin{aligned} &设f(n)=\sum_{i=1}^{n-1}gcd(i,n)\\ &那么ans=\sum_{i=1}^{n}f(n)\\ f(n)&=\sum_{d|n}d\times\sum_{i=1}^{n-1}[gcd(i,n)=d]\\ &=\sum_{d|n}d\times\sum_{i=1}^{\frac{n}{d}-1}[gcd(i,\frac{n}{d})=1]\\ &=\sum_{d|n}d\times \phi(\frac{n}{d}) \end{aligned}
f(n)设f(n)=i=1∑n−1gcd(i,n)那么ans=i=1∑nf(n)=d∣n∑d×i=1∑n−1[gcd(i,n)=d]=d∣n∑d×i=1∑dn−1[gcd(i,dn)=1]=d∣n∑d×ϕ(dn)
那么我们就可以在预处理欧拉函数后,用类似埃氏筛的方法,预处理出
f
(
n
)
f(n)
f(n),最后对其做一遍前缀和,就得到了最终的答案。
此处给出筛 f ( n ) f(n) f(n)的代码:
for(int i = 1; i*i < MAX; i++){
ans[i*i] += i*phi[i];
for(int j = i+1; i*j < MAX; j++){
ans[i*j] += phi[j]*i+phi[i]*j;
}
}
由于 d d d和 n d \frac{n}{d} dn是对称的,我们直接一次累计即可,但对于平方数,只能累计一个答案。
于是你又可以A掉SP3871,UVA11424和UVA11426.
至此,恭喜你成功用1个套路水掉了七倍经验!!