整除分块

目录

目录地址

上一篇

下一篇


整除函数

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

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

例如:

\(\lfloor3.1\rfloor=\lfloor3\rfloor=3\)

\(\lceil3.1\rceil=\lceil4\rceil=4\)

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

\(\lfloor x\rfloor\leq x<\lfloor x\rfloor+1\)

\(\lceil x\rceil-1<x\leq \lceil x\rceil\)

整除函数的实现

#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\neq 0,0\leq r<m)\) 若满足带余除法式:

\(n\div m=k\cdots r\)

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

显然,我们可以得到:\(k\leq {n\over m}={km+r\over m}=k+{r\over m}<k+{m\over m}=k+1\)

简单来写,就是 \(k\leq {n\over m}<k+1\)

这里有一个很巧妙的转化:考虑到 \(k\in N,\lfloor{n\over m}\rfloor\leq {n\over m}<\lfloor{n\over m}\rfloor+1\)

因此 \(k=\lfloor{n\over m}\rfloor\)

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

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


商的个数

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

证明:

对于除数 \(m\in Z_+\)

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

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

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

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

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

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

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


整除分块

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

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

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

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

我们先考虑:假设对于 \(\forall i\in[l,r]\bigcap Z\) 都有 \(\lfloor{n\over l-1}\rfloor\neq \lfloor{n\over l}\rfloor=\lfloor{n\over i}\rfloor=\lfloor{n\over r}\rfloor\neq \lfloor{n\over r+1}\rfloor\)

\(\therefore \displaystyle \sum_{i=l}^r\lfloor{n\over i}\rfloor=\sum_{i=1}^r\lfloor{n\over l}\rfloor=\lfloor{n\over l}\rfloor(r-l+1)\)

那么,若我们能已知所有的 \(l,r\) 即可递推出:\(\displaystyle \sum_{i=1}^n\lfloor{n\over i}\rfloor=\sum\lfloor{n\over l}\rfloor(r-l+1)\)

注意到:\(\lfloor{n\over l-1}\rfloor\neq \lfloor{n\over l}\rfloor=\lfloor{n\over r}\rfloor\neq \lfloor{n\over r+1}\rfloor\)

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

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

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


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

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

而对于区间 \([l,r]\) ,由于 \(\forall i\in[l,r]\bigcap Z\) 都有 \(\lfloor{n\over l-1}\rfloor\neq \lfloor{n\over l}\rfloor=\lfloor{n\over i}\rfloor=\lfloor{n\over r}\rfloor\neq \lfloor{n\over r+1}\rfloor\)

\(r=max(i)\) 得出 \({n\over r}=min({n\over i})\geq \lfloor{n\over l}\rfloor\)

所以有 \(r\leq {n\over \lfloor{n\over l}\rfloor}\)

考虑到 \(r\in Z_+\)\(r=\lfloor{n\over \lfloor{n\over l}\rfloor}\rfloor\)

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


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

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

而同上可以得出 \(l=min(i)\) 从而有 \({n\over l}=max({n\over i})< \lfloor{n\over r}\rfloor+1\)

因此有 \(l> {n\over \lfloor{n\over r}\rfloor+1}\)

同样考虑 \(l\in Z_+\)\(l=\lfloor{n\over \lfloor{n\over r}\rfloor+1}+1\rfloor=\lfloor{n\over \lfloor{n\over r}\rfloor+1}\rfloor+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 i\in[1,k]\bigcap Z,\lfloor{n\over i}\rfloor\) 有关

从左往右整出分块:

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\) )的用从左往右更方便(因为代码更好记)

posted @ 2020-02-23 09:53  JustinRochester  阅读(502)  评论(0编辑  收藏  举报