什么是数论分块(好像也有叫除法分块的)?
例题
求以 N N N为被除数,在 [ 0 , N ] [0,N] [0,N]的范围内,将所得的商向下取整相同的所有除数区间。 N ∈ [ 0 , 1 0 9 ] N∈[0,10^9] N∈[0,109]
很显然应该考虑维护除数区间的左、右端点。怎么更新?
首先设
L
,
R
L,R
L,R。初始化
L
=
R
=
1
L=R=1
L=R=1。
显然更新的时候
L
′
=
R
+
1
L'=R+1
L′=R+1,
R
′
R'
R′呢?不难得到
R
′
=
⌊
N
⌊
N
L
′
⌋
⌋
R'=\left\lfloor\frac{N}{\left\lfloor\frac{N}{L'}\right\rfloor}\right\rfloor
R′=⌊⌊L′N⌋N⌋
把除数按照
N
\sqrt{N}
N分成两类,
≤
N
\le\sqrt{N}
≤N的部分复杂度显然是
Θ
(
N
)
\Theta(\sqrt{N})
Θ(N)。
大于
N
\sqrt{N}
N的部分因为商
≤
N
\le\sqrt{N}
≤N显然复杂度也是
Θ
(
N
)
\Theta(\sqrt{N})
Θ(N)。综上所述。
然后我们发现数论分块其实是我们在不知道名字的情况下可能已经见了好多次的套路(
这道题目要求的东西显然可以转化为前缀和相减,考虑前缀和怎么求。
∑
i
=
1
n
f
(
i
)
\sum\limits_{i=1}^n f(i)
i=1∑nf(i)其中
f
(
i
)
=
∑
d
∣
i
d
f(i)=\sum\limits_{d|i}d
f(i)=d∣i∑d所以我们要求的东西是
∑
i
=
1
n
∑
d
∣
i
d
\sum\limits_{i=1}^n\sum\limits_{d|i}d
i=1∑nd∣i∑d
这个形式看起来有点熟悉? f ( i ) = σ ( i ) f(i)=\sigma(i) f(i)=σ(i),然后我们知道 σ = 1 ∗ i d \sigma=1*id σ=1∗id
然后有 μ ∗ σ = i d \mu*\sigma=id μ∗σ=id,因为要求的是 σ ( i ) \sigma(i) σ(i)的前缀和,然后可以把 μ ( i ) \mu(i) μ(i)作为 g ( x ) g(x) g(x)杜教筛
emmm可是我是不会杜教筛的小蒟蒻,怎么做哇?
首先考虑一下怎么暴力,显然可以
Θ
(
N
N
)
\Theta(N\sqrt{N})
Θ(NN)完美TLE
但是注意到我们把同一个约数可能枚举了好多次;考虑枚举d?好像就可以
N
\sqrt{N}
N
考虑一个d出现了几次:
⌊
N
d
⌋
\left\lfloor\frac{N}{d}\right\rfloor
⌊dN⌋。于是可以得到d对答案的贡献是
d
⌊
N
d
⌋
d\left\lfloor\frac{N}{d}\right\rfloor
d⌊dN⌋
但是呢就算改成了枚举约数,我们还是需要
Θ
(
N
)
\Theta(N)
Θ(N)的复杂度
emm 先整理一下现在需要求的东西吧:
∑
d
=
1
n
d
⌊
N
d
⌋
\sum\limits_{d=1}^nd\left\lfloor\frac{N}{d}\right\rfloor
d=1∑nd⌊dN⌋
好像里面有不小一部分的
⌊
N
d
⌋
\left\lfloor\frac{N}{d}\right\rfloor
⌊dN⌋空了?
⌊
N
d
⌋
\left\lfloor\frac{N}{d}\right\rfloor
⌊dN⌋……除法分块?
然后这道题目就可以用
Θ
(
N
)
\Theta(\sqrt{N})
Θ(N)的时间复杂度解决了。
#include<cstdio>
using namespace std;
long long Calc(const long long &N) {
long long Ans = 0;
for (register long long x, L = 1, R; L <= N; L = R + 1) {
x = N / L;
R = N / x;
Ans += (L + R) * (R - L + 1) / 2 * x;
}
return Ans;
}
int main() {
long long X = 0, Y = 0;
scanf("%lld%lld", &X, &Y);
printf( "%lld", Calc(Y) - Calc(X - 1) );
return 0;
}