整除分块,数论分块

文章介绍了数论中的整除定理,并展示了如何使用整除分块方法快速计算特定的和式,包括从左端点和从右端点计算的两种方法。此外,还探讨了向下取整和向上取整分块的原理和应用,以及如何将该技术扩展到带有函数的求和问题中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数论分块

整除定理

整除定理事实上是两个式子:
⌊ a b c ⌋ = ⌊ ⌊ a b ⌋ c ⌋ \left\lfloor\frac a {bc}\right\rfloor=\left\lfloor\frac{\lfloor\frac a b\rfloor}c\right\rfloor bca=cba

⌈ a b c ⌉ = ⌈ ⌈ a b ⌉ c ⌉ \left\lceil\frac a {bc}\right\rceil=\left\lceil\frac{\lceil\frac a b\rceil}c\right\rceil bca=cba

a , b , c ∈ N a,b,c\in\mathbb{N} a,b,cN

参照(3.4)、(3.5)的证明

商定理

∀ n ∈ N + : ∣ { ⌊ n i ⌋ ∣ i ∈ [ 1 , n ] ∩ Z } ∣ = O ( n ) \forall n\in\mathbb{N}^+:\left|\left\{{\left\lfloor{\frac n i}\right\rfloor}|i\in[1,n]\cap\mathbb{Z}\right\}\right|=O(\sqrt n) nN+: {ini[1,n]Z} =O(n )

也就是说: ⌊ n i ⌋ \left\lfloor{\frac n i}\right\rfloor in至多有 O ( n ) O(\sqrt n) O(n )种取值。

这很显然,因为对于 i ≤ n i\leq \sqrt n in ,至多有 n \sqrt n n i i i ⌊ n i ⌋ \left\lfloor{\frac n i}\right\rfloor in至多有 n \sqrt n n 种取值。
对于 i > n i>\sqrt n i>n 1 ≤ n i < n 1\leq\frac n i <\sqrt n 1in<n ,也至多有 O ( n ) O(\sqrt n) O(n )种取值。

方法一

整除分块用于快速求以下和式:
∑ i = 1 n ⌊ n i ⌋ \overset{n}{\underset{i=1}\sum}\left\lfloor{\frac n i}\right\rfloor i=1nin

我们注意到, ⌊ n i ⌋ \left\lfloor{\frac n i}\right\rfloor in至多有 O ( n ) O(\sqrt n) O(n )种取值,而且显然相同的取值分布于连续的块内。

当我们计算到了一个块 x x x内时,一开始必然处于块的左端点 l l l,我们只需要快速计算出块的右端点 r r r,即可快速计算块内的贡献。

根据结论 r = n / ( n / l ) r=n/(n/l) r=n/(n/l),我们可以快速计算右端点,因此可以整除分块。
结论以及证明在下面。

因此可以整除分块:

#include<iostream>
using namespace std;
long long calc(long long n) {
	long long sum=0;
	for(long long l=1,r;l<=n;l=r+1) 
		r=n/(n/l),
		sum+=n/l*(r-l+1);
	return sum;
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--) {
		int x;
		cin>>x;
		cout<<calc(x)<<endl;
	}
	
}

或:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
long long calc(long long n) {
	long long sum=0;
	for(long long l,r=n;r>=1;r=l-1) {
		l=(n/(n/r+1))+1;
		sum+=n/l*(r-l+1);
	}
	return sum;
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--) {
		int x;
		cin>>x;
		cout<<calc(x)<<endl;
	}
	
}

从左端点计算右端点是非常容易的,也是普遍使用的整除分块写法。

向下取整分块

结论:对于 i i i处于权值为 ⌊ n i ⌋ {\left\lfloor{\frac ni}\right\rfloor} in的块内,块对应的定义域为 i ∈ [ 1 + ⌊ n ⌊ n i ⌋ + 1 ⌋ , ⌊ n ⌊ n i ⌋ ⌋ ] i\in\left[1+{\left\lfloor{\frac{n}{\left\lfloor{\frac ni}\right\rfloor+1}}\right\rfloor},{\left\lfloor{\frac n{\left\lfloor{\frac ni}\right\rfloor}}\right\rfloor}\right] i[1+in+1n,inn]

证明:
我们注意到:
⌊ n i ⌋ ≤ n i < ⌊ n i ⌋ + 1 {\left\lfloor{\frac ni}\right\rfloor}\leq\frac ni<{\left\lfloor{\frac ni}\right\rfloor}+1 inin<in+1,这个条件是充要的,即: R n i = [ ⌊ n i ⌋ , ⌊ n i ⌋ + 1 ) R_\frac ni=\left[{\left\lfloor{\frac ni}\right\rfloor},{\left\lfloor{\frac ni}\right\rfloor}+1\right) Rin=[in,in+1),其中 R R R表示值域。

我们对这个条件做不等式的充分必要变换(即不存在不等式放缩),得到:
{ i ≤ n ⌊ n i ⌋ n ⌊ n i ⌋ + 1 < i \left\{\begin{matrix} i\leq\frac n{\left\lfloor{\frac ni}\right\rfloor}\\ \frac{n}{{\left\lfloor{\frac ni}\right\rfloor}+1}<i \end{matrix}\right. {iinnin+1n<i

对第二个不等式做处理,得到:
{ i ≤ n ⌊ n i ⌋ 1 + ⌊ n ⌊ n i ⌋ + 1 ⌋ ≤ i \left\{\begin{matrix} i\leq\frac n{\left\lfloor{\frac ni}\right\rfloor}\\ 1+\left\lfloor\frac{n}{{\left\lfloor{\frac ni}\right\rfloor}+1}\right\rfloor\leq i \end{matrix}\right. iinn1+in+1ni

因为 i ∈ Z : i\in\mathbb{Z}: iZ:
{ i ≤ ⌊ n ⌊ n i ⌋ ⌋ 1 + ⌊ n ⌊ n i ⌋ + 1 ⌋ ≤ i \left\{\begin{matrix} i\leq\left\lfloor\frac n{\left\lfloor{\frac ni}\right\rfloor}\right\rfloor\\ 1+\left\lfloor\frac{n}{{\left\lfloor{\frac ni}\right\rfloor}+1}\right\rfloor\leq i \end{matrix}\right. iinn1+in+1ni

QED.

向上取整分块

结论:对于 i i i处于权值为 ⌈ n i ⌉ {\left\lceil{\frac ni}\right\rceil} in的块内,块对应的定义域为 i ∈ [ ⌈ n ⌈ n i ⌉ ⌉ , ⌈ n ⌈ n i ⌉ − 1 ⌉ − 1 ] i\in\left[{\left\lceil{\frac n{\left\lceil{\frac ni}\right\rceil}}\right\rceil},{\left\lceil{\frac n{\left\lceil{\frac ni}\right\rceil-1}}\right\rceil}-1\right] i[inn,in1n1]

证明:
⌈ n i ⌉ − 1 < n i ≤ ⌈ n i ⌉ {\left\lceil{\frac ni}\right\rceil}-1<\frac ni\leq{\left\lceil{\frac ni}\right\rceil} in1<inin
则: { n ⌈ n i ⌉ ≤ i i < n ⌈ n i ⌉ − 1 \left\{\begin{matrix} \frac n{\left\lceil{\frac ni}\right\rceil}\leq i\\ i<\frac n{{\left\lceil{\frac ni}\right\rceil}-1} \end{matrix}\right. {innii<in1n
即: { ⌈ n ⌈ n i ⌉ ⌉ ≤ i i ≤ ⌈ n ⌈ n i ⌉ − 1 ⌉ − 1 \left\{\begin{matrix} \left\lceil\frac n{\left\lceil{\frac ni}\right\rceil}\right\rceil\leq i\\ i\leq\left\lceil\frac n{{\left\lceil{\frac ni}\right\rceil}-1}\right\rceil-1 \end{matrix}\right. inniiin1n1

这个条件是充要的,证毕。

方法二

此方法仅供参考。

求以下和式:
∑ i = 1 n ⌊ n i ⌋ \overset{n}{\underset{i=1}\sum}\left\lfloor{\frac n i}\right\rfloor i=1nin

假设目前在 i i i位置,我们考虑构造带余除法 n = p ⋅ i + q n= p\cdot i+q n=pi+q,其中 p p p则为 ⌊ n i ⌋ \left\lfloor\frac n i\right\rfloor in
注意 i i i为除数, p p p为整除的结果, q q q为余数。

i i i向左移动1次,则 n = p ⋅ ( i − 1 ) + ( q + p ) n=p\cdot (i-1)+(q+p) n=p(i1)+(q+p)
向左移动 k k k次,则 n = p ⋅ ( i − k ) + ( q + k ⋅ p ) n=p\cdot (i-k)+(q+k\cdot p) n=p(ik)+(q+kp)

p p p发生改变,当且仅当 i − k ≤ q + k ⋅ p i-k\leq q+k\cdot p ikq+kp,也就是 i − q ≤ k ( 1 + ⌊ n i ⌋ ) i-q\leq k\left(1+\left\lfloor\frac n i\right\rfloor\right) iqk(1+in)
因而: k ≥ i − q n / i + 1 k\geq\frac {i-q}{n/i+1} kn/i+1iq
注意到 q q q是余数: k ≥ i − n    m o d    i n / i + 1 k\geq\frac {i-n\;mod\;i}{n/i+1} kn/i+1inmodi
我们应该取到最小的 k k k,只有这样才使得 k k k是块长: k = ⌈ i − n    m o d    i n / i + 1 ⌉ k=\left\lceil\frac {i-n\;mod\;i}{n/i+1}\right\rceil k=n/i+1inmodi

代码很细节:

#include<iostream>
#include<cmath>
using namespace std;
long long H(long long n) {
	long long sum=0;
	for(long long i=n,k;i>=1;i-=k) {
		k=ceil(double(i-n%i)/(n/i+1));
		sum+=n/i*k;
	}
	return sum;
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--) {
		long long x;
		cin>>x;
		cout<<H(x)<<endl;
	}
	return 0;
}

通过这种方法可以求出其他情况下的范围,但是我懒得推了。

练习题

更复杂情况:

若要计算:
∑ i = 1 n f ( i ) ⌊ n i ⌋ \overset{n}{\underset{i=1}\sum}f(i)\left\lfloor\frac n i\right\rfloor i=1nf(i)in,则初始化出 f f f函数的前缀和,记作 g g g,再分块计算即可,也就是这样:
∑ i = 1 n f ( i ) ⌊ n i ⌋ = ∑ l , r ( g ( r ) − g ( l − 1 ) ) ⌊ n l ⌋ \overset{n}{\underset{i=1}\sum}f(i)\left\lfloor\frac n i\right\rfloor={\underset{l,r}\sum}(g(r)-g(l-1))\left\lfloor\frac n l\right\rfloor i=1nf(i)in=l,r(g(r)g(l1))ln

练习题

后记

其实还有一些像是这样的东西: ∑ n i = 1 ⌊ n i 3 ⌋ \underset{i=1}{\overset{n}\sum}\left\lfloor\frac n {i^3}\right\rfloor i=1ni3n,但是这个不在我们今天讨论的范围之内了。

于是皆大欢喜。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值