• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
数论分块

数论分块

如何在\(O(\sqrt{n})\)复杂度内计算 \(\sum \limits_{i= 1}^n \lfloor \frac{n}{i} \rfloor\) ?

一个直观的想法是, \(\lfloor \frac{i}{n} \rfloor\) 必然存在一个相等的段,我们以\(n = 15\) 为例:

\[\lfloor \frac{n}{i} \rfloor (n=15) \\ \]

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
15 7 5 3 3 2 2 2 1 1 1 1 1 1 1

我们可以看到该段区间内当 \(n\) 取值为 \([6, 8], [9, 15]\)内的值都是相等的值,我们考虑如何以每个这样的块为单位来计算要求的值。

考虑左端点为 \(l\), 我们设右端点为 \(r\), 有如下等式

\[\because \lfloor \frac{n}{r} \rfloor \le \frac{n}{r} \\ \therefore r \le \frac{n}{\lfloor \frac{n}{r} \rfloor} \\ 又\because \lfloor \frac{n}{l} \rfloor = \lfloor \frac{n}{r} \rfloor, 且 r取值为整数 \\ \therefore r_{max} = \frac{n}{\lfloor \frac{n}{l} \rfloor} \]

例题

CQOI2007-余数求和

#include <iostream>

using i64 = long long;

int main() {
	i64 n, k; std::cin >> n >> k;

	i64 sum = 0;

	i64 l = 1, r = 0;

	while (l <= k && l <= n) {
		r = std::min(k / (k / l), n);

		i64 t = r - l + 1;

		sum += t * k - (l + r) * t / 2 * (k / l);

		l = r + 1;	
	}	

	std::cout << sum + std::max(0LL, 1LL * (n - k) * k);
}
posted on 2023-11-24 20:10  Jack404  阅读(12)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3