整除分块
Glassy_Sky
·
·
个人记录
整除分块
在解决 {\sum \limits_{i=1}^{n} \lfloor \frac{n}{i} \rfloor } 这样的问题时,如果用暴力计算,效率显然是十分低下的。
所以这里引入整除分块算法,仅用 {O( \sqrt{n} )} 的复杂度。
下面以 {n=8} 为例。
观察上面第二行的值,发现是逐步变小的,而且是一段一段相等的数。
于是乎,为了快速求和,我们就给它一段一段求和。
即:数值 乘上 个数。
可以发现每一种值都是 {n} 的约数,所以这样的枚举不会超过 {2\sqrt{n}} 个,那么它的复杂度也就有了保证。
复杂度:{O(2\sqrt{n})}
参考代码:
long long get(long long n) {
long long ans=0;
for(long long l=1,r;l<=n;l=r+1) {
r=n/(n/l);
ans+=(r-l+1)*(n/l);
}
return ans;
}
证明:
先让 {l} 为分块的左边界,那么这块的单个值 {k= \lfloor \frac{n}{l} \rfloor} ,这样右边界 {r} 就是值为 {k} 的最大下标 {i} ,也就是说要找满足 {i \leqslant \frac{n}{k}} 的最大的 {i} ,即 {r=max(i)=\lfloor \frac{n}{k}} ,将 {k} 代入,得到 {r=\lfloor \frac{n}{\lfloor \frac{n}{l} \rfloor} \rfloor} 。
# 例题:[P2261 [CQOI2007]余数求和](https://www.luogu.com.cn/problem/P2261)
## 题目描述
给出正整数 $n$ 和 $k$,请计算
$$G(n, k) = \sum_{i = 1}^n k \bmod i$$
其中 $k\bmod i$ 表示 $k$ 除以 $i$ 的余数。
## 输入格式
输入只有一行两个整数,分别表示 $n$ 和 $k$。
## 输出格式
输出一行一个整数表示答案。
## 样例 #1
### 样例输入 #1
```
10 5
```
### 样例输出 #1
```
29
```
## 提示
#### 样例 1 解释
$G(10, 5)=0+1+2+1+0+5+5+5+5+5=29$。
#### 数据规模与约定
- 对于 $30\%$ 的数据,保证 $n , k \leq 10^3$。
- 对于 $60\%$ 的数据,保证 $n, k \leq 10^6$。
- 对于 $100\%$ 的数据,保证 $1 \leq n, k \leq 10^9$。
**参考程序:**
```cpp
#include<bits/stdc++.h>
using namespace std;
long long n,k,ans=0;
int main() {
cin>>n>>k;
ans=n*k;
for(long long l=1,r;l<=min(n,k);l=r+1) {
r=k/(k/l);
if(r>n) r=n;
ans-=(k/l)*((l+r)*(r-l+1)/2);
}
cout<<ans;
return 0;
}
```
**题解:**
首先我们要清楚: ${ a \% b = a - \lfloor \frac{a}{b} \rfloor \times b}$ .
所以原式可以化为:${nk - \sum \limits_{i=1}^{n} \lfloor \frac{k}{i} \rfloor \times i}$ .
结合刚才学的结合分块,相信大家都会做了。
-------------