[Luogu2424] 约数和 [数论分块]

[ L i n k \frak{Link} Link]


什么是数论分块(好像也有叫除法分块的)?

例题
求以 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=LNN
把除数按照 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=1nf(i)其中 f ( i ) = ∑ d ∣ i d f(i)=\sum\limits_{d|i}d f(i)=did所以我们要求的东西是 ∑ i = 1 n ∑ d ∣ i d \sum\limits_{i=1}^n\sum\limits_{d|i}d i=1ndid

这个形式看起来有点熟悉? f ( i ) = σ ( i ) f(i)=\sigma(i) f(i)=σ(i),然后我们知道 σ = 1 ∗ i d \sigma=1*id σ=1id
然后有 μ ∗ σ = 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 ddN
但是呢就算改成了枚举约数,我们还是需要 Θ ( N ) \Theta(N) Θ(N)的复杂度


emm 先整理一下现在需要求的东西吧: ∑ d = 1 n d ⌊ N d ⌋ \sum\limits_{d=1}^nd\left\lfloor\frac{N}{d}\right\rfloor d=1nddN
好像里面有不小一部分的 ⌊ 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值