1 条题解
-
1
题目分析
题意简述
给定两个整数 和 (),计算 ,即 对 到 每个数取模后的总和。
输入
- 输入包含多组测试用例,每组给出 和 。
输出
- 对于每组测试用例,输出所求的和。
解题思路
直接计算的问题
直接遍历 从 到 计算 并累加,时间复杂度为 。当 和 很大时(如 ),这种暴力方法会超时。
数学优化
观察到:
- 当 时,,因此这部分的和可以直接计算为 (如果 )。
- 当 时,$k \bmod i = k - i \times \lfloor \frac{k}{i} \rfloor$。可以利用数论分块优化计算:
- 对于固定的 , 的取值范围是 $\left[ \lfloor \frac{k}{q+1} \rfloor + 1, \lfloor \frac{k}{q} \rfloor \right]$。
- 通过分块计算,将时间复杂度从 降低到 。
算法步骤
- 处理 的情况:直接计算 。
- 处理 的情况:
- 使用数论分块,枚举 的所有可能值。
- 对于每个 ,计算对应的 的范围,并累加 的总和。
代码实现
#include <cstdio> #include <cstdlib> // 添加exit函数 using namespace std; int main() { long long k, n; while (scanf("%lld%lld", &n, &k) == 2) { if (k == 0) { // 处理k=0的特殊情况 printf("0\n"); continue; } long long ans = 0; // 处理i > k的情况 if (n > k) { ans += (n - k) * k; n = k; } // 处理i <= k的情况 long long p = 1; for (int i = 1; ; i++) { if (k / i <= k / (i + 1) + 2) { p = i; break; } } if (n <= k / (p + 1)) { for (int i = 1; i <= n; i++) { ans += k % i; } printf("%lld\n", ans); continue; } for (int i = p; i >= 1; i--) { long long cnt = k / i - k / (i + 1); long long t = k % (k / i) + (cnt - 1) * i; if (n < k / (i + 1) + 1) break; if (n < k / i) cnt = n - k / (i + 1); ans += cnt * (2 * t + (1 - cnt) * i) / 2; } for (int i = 1; i <= k / (1 + p); i++) { ans += k % i; } printf("%lld\n", ans); } return 0; }
代码说明
- 输入处理
- 使用
scanf
读取多组测试用例的 和 。
- 使用
- 直接计算 的部分
- 如果 ,直接计算 并累加到答案中。
- 数论分块优化
- 通过枚举 的值,分块计算 的总和。
- 使用等差数列求和公式加速计算。
- 边界处理
- 对于较小的 ,直接暴力计算;对于较大的 ,利用分块结果。
复杂度分析
- 时间复杂度:,主要来自数论分块的枚举。
- 空间复杂度:,仅使用常数空间。
示例
输入样例 1
5 3
输出样例 1
7
解释
$3 \bmod 1 + 3 \bmod 2 + 3 \bmod 3 + 3 \bmod 4 + 3 \bmod 5 = 0 + 1 + 0 + 3 + 3 = 7$。
- 1
信息
- ID
- 1801
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者