整除分块

Posted justinrochester

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了整除分块相关的知识,希望对你有一定的参考价值。

目录

目录地址

上一篇

下一篇


整除函数

我们定义下取整函数 (floor(x)=lfloor x floor) 表示不大于 (x) 的最小整数

另外,定义上取整函数 (ceil(x)=lceil x ceil) 表示不小于 (x) 的最小整数

例如:

(lfloor3.1 floor=lfloor3 floor=3)

(lceil3.1 ceil=lceil4 ceil=4)

我们可以得到两个很显然的性质:

(lfloor x floorleq x<lfloor x floor+1)

(lceil x ceil-1<xleq lceil x ceil)

整除函数的实现

#include<cmath>
...
x=floor(x);//x=ceil(x)

考虑除法情况下的整除函数实现:

x=n/m;//x=floor(n/m)
x=n/m+(n%m!=0)//x=ceil(n/m)

取商除法

对于自然数 (n,m,k,r(m eq 0,0leq r<m)) 若满足带余除法式:

(ndiv m=kcdots r)

则称呼 (n) 为被除数, (m) 为除数, (k) 为商, (r) 为余数

显然,我们可以得到:(kleq {nover m}={km+rover m}=k+{rover m}<k+{mover m}=k+1)

简单来写,就是 (kleq {nover m}<k+1)

这里有一个很巧妙的转化:考虑到 (kin N,lfloor{nover m} floorleq {nover m}<lfloor{nover m} floor+1)

因此 (k=lfloor{nover m} floor)

因为本人是 C++ 选手,因此,习惯性的将之写为 (k=n/m)

即本人表示一下:在本人后期的贴子中,可能出现的 (n/m)(lfloor{nover m} floor) ,与 ({nover m}) 区分


商的个数

对于被除数 (n) ,它的商的个数一定不超过 ((2sqrt n+1))

证明:

对于除数 (min Z_+)

(mleq sqrt n) ,则商 (n/m) 的取值个数一定不超过 (m) 的个数

因此商 (n/m) 的取值个数一定不超过 (sqrt n)

(m>sqrt n) ,则商 ({nover m}) 的取值范围为 ([0,sqrt n))

因此 (n/m) 的取值个数一定不超过该区间内的整数个数,因此不超过 ((sqrt n+1))

两部分相加,因此,商的个数不超过 ((2sqrt n+1))

而特殊的,如保证 (mleq n) ,则另外可保证商的个数不超过 (2sqrt n)

即扣除了商为 (0) 的情况


整除分块

(除数的范围为 (1)~(n) )

考虑到被除数 (n) 的商个数是 (O(sqrt n)) 级别的

因此当题目需要考虑的是 (forall iin Z_+,lfloor{nover i} floor) 时,我们可以通过枚举这 ((2sqrt n+1)) 个商来实现

这样一来,我们可以把时间复杂度从 (O(n)) 降低至 (O(sqrt n))

我们先考虑:假设对于 (forall iin[l,r]igcap Z) 都有 (lfloor{nover l-1} floor eq lfloor{nover l} floor=lfloor{nover i} floor=lfloor{nover r} floor eq lfloor{nover r+1} floor)

( herefore displaystyle sum_{i=l}^rlfloor{nover i} floor=sum_{i=1}^rlfloor{nover l} floor=lfloor{nover l} floor(r-l+1))

那么,若我们能已知所有的 (l,r) 即可递推出:(displaystyle sum_{i=1}^nlfloor{nover i} floor=sumlfloor{nover l} floor(r-l+1))

注意到:(lfloor{nover l-1} floor eq lfloor{nover l} floor=lfloor{nover r} floor eq lfloor{nover r+1} floor)

因此,如果我们知道 (l)(r) ,就能递推出下一个区间的 (r)(l)

所以,我们选 (l) 或选 (r) 的关键就在于:

已知这个区间的 (l)(r) ,能否推出另一个?如果能的话,就能根据推出的另一端,再推出下一个区间的 (l)(r) ,然后循环至全部区间推出


我们先考虑已知左端点 (l)

第一个 (l) 一定为 (1)

而对于区间 ([l,r]) ,由于 (forall iin[l,r]igcap Z) 都有 (lfloor{nover l-1} floor eq lfloor{nover l} floor=lfloor{nover i} floor=lfloor{nover r} floor eq lfloor{nover r+1} floor)

(r=max(i)) 得出 ({nover r}=min({nover i})geq lfloor{nover l} floor)

所以有 (rleq {nover lfloor{nover l} floor})

考虑到 (rin Z_+)(r=lfloor{nover lfloor{nover l} floor} floor)

为避免混淆,我们记为 (r=n/(n/l))


再考虑已知右端点 (r) :

第一个 (r) 一定为 (n)

而同上可以得出 (l=min(i)) 从而有 ({nover l}=max({nover i})< lfloor{nover r} floor+1)

因此有 (l> {nover lfloor{nover r} floor+1})

同样考虑 (lin Z_+)(l=lfloor{nover lfloor{nover r} floor+1}+1 floor=lfloor{nover lfloor{nover r} floor+1} floor+1)

为避免混淆,我们记为 (l=n/(n/r+1)+1)


整除分块的实现

由上面的推导可知

从左往右整除分块:

for(int l=1,r;l<=n;l=r+1){
    int d=n/l;
    r=n/d;
    ......
}

从右往左整出分块:

for(int r=n,l;r>=1;r=l-1){
    int d=n/r;
    l=n/(d+1)+1;
    ......
}

整出分块的一般形式

给定 (n,k) 所求式与 (forall iin[1,k]igcap Z,lfloor{nover i} floor) 有关

从左往右整出分块:

for(int l=1,r;l<=k;l=r+1){
    int d=n/l;
    r=Min(n/d,k);
    ......
}

从右往左整出分块:

for(int r=k,l;r>=1;r=l-1){
    int d=n/r;
    l=n/(d+1)+1;
    ......
}

同样的,考虑给定下界、同时给定上下界的整出分块

我们发现,实际上,给定上界的整出分块用从右往左更方便;其余情况(给定下界、给定上下界、范围为 (1)~(n) )的用从左往右更方便(因为代码更好记)

以上是关于整除分块的主要内容,如果未能解决你的问题,请参考以下文章

数论分块之整除分块

整除分块

C. Everyone is a Winner!(整除分块)

整除分块

整除分块模板

整除分块小记