整除分块

整除分块

在解决 \({\sum \limits_{i=1}^{n} \lfloor \frac{n}{i} \rfloor }\) 这样的问题时,如果用暴力计算,效率显然是十分低下的。

所以这里引入整除分块算法,仅用 \({O( \sqrt{n} )}\) 的复杂度。


下面以 \({n=8}\) 为例。

1

观察上面第二行的值,发现是逐步变小的,而且是一段一段相等的数。

于是乎,为了快速求和,我们就给它一段一段求和。

即:数值 乘上 个数。

可以发现每一种值都是 \({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}\)

\({tip:}\) 只要 \({i}\) 取值 \({[l,r)}\) ,则 \({ r=\lfloor \frac{n}{\lfloor \frac{n}{i} \rfloor} \rfloor }\).

例题:P2261 [CQOI2007]余数求和

题目描述

给出正整数 \(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\)

参考程序:

#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}\) .

结合刚才学的结合分块,相信大家都会做了。


posted @ 2023-04-29 07:01  ForBiggerWorld  阅读(30)  评论(0)    收藏  举报