约数之和
Description
Consider two natural numbers A and B. Let S be the sum of all natural divisors of
考虑两个自然数 A 和 B。设 S 为
所有自然除数的之和。求 S 除以 9901 的余数。
Input
The only line contains the two natural numbers A and B, (
Output
The only line of the output will contain S modulo 9901.
Sample Input
1 | 2 3 |
Sample Output
1 | 15 |
The natural divisors of 8 are: 1,2,4,8. Their sum is 15.
15 modulo 9901 is 15 (that should be output).
Limit
| Time Limit | Memory Limit |
|---|---|
| 1 秒(C/C++/Rust/Pascal);2 秒(其他语言) | 32 M(C/C++/Rust/Pascal);64 M(其他语言) |
Analysis
分析样例,对于
假设通过函数
证明:
根据算术基本原理,设
那么
它的所有约数的普遍形式是
公式生成的两个集合分别能覆盖的范围:
- 左半边
:
这里的约数指数不能超过。所以覆盖的范围是 且 。 - 右半边
:
因为乘了一个(也就是乘了 ),原来集合里的 和 同时加了 1。
所以覆盖的范围是且 。
会遗漏极端情况,比如
故猜想不正确,不过根据因数构造新因数的思想应该是没问题的。
换一个思路,由「算术基本原理」:
每个大于 1 的自然数,要么本身是质数,要么可以写成若干个质数的乘积,且如果不计较质数的排列顺序,这种写法是唯一的。任意正整数 n 可以写成
其中 p 是质数,a 是指数。
在本题,有:
而
那么本题的要求可表示为:
接下来需要化简该公式以便于编程。
假设有一个数
根据约数的构造规律,它的任何一个约数
它的所有约数之和
现在,我们逆用乘法分配律。
首先,按照
- 提取第一组的
: - 提取第二组的
: - 提取第三组的
:
代入原式:
此时发现,
注:
这是一个等比数列的累乘,更方便编程求解。
推广到
简写为:
由于括号内是首项为
本题要求计算
Solve
对于质因数的分解,有这样的
1 | void div(int val) { |
对于
1 | int power(int i, int j) { |
对于等比数列求和部分
为了避开求逆元和特判的麻烦,我们可以使用分治法来计算等比数列的和。设
利用二分思想,我们可以将整个多项式从中间劈开,按
- 当
为奇数时:
整个数列共有项(偶数项),可以完美平分为前后两半。
我们把后半部分的公因式
合并同类项,得到化简后的递推式:
- 当
为偶数时:
数列共有项(奇数项),无法平分。我们可以先把最后一项 单独拿出来,此时前面剩下的项最高次幂为 (奇数),就可以复用上面的平分逻辑了。
对前半部分进行平分提取(由于最高次幂是
这种分治求和的方法,每次递归都会让
代码实现如下:
1 | int sum(int p, int c) { |
最终实现如下:
1 |
|
在 divsum 函数中,使用 for(int i = 2; i <= num / i; ++i) 来寻找质因子。
- 在最坏情况下(例如
本身是质数),循环会执行到 。 - 内层的
while(num % i == 0)不断做除法,所有这些除法的总执行次数严格受限于。 - 这一部分的时间复杂度为
。
对于每一个找出的质因子,都会调用 sum(i, p * b) 计算等比数列和。
- 设
有 个不同的质因子,最多调用 次 sum函数。由于,在给定的数据范围内 ,可视为极小的常数。 - 在单次
sum(p, c)中,递归深度为,每次递归内部又调用了时间复杂度为 的 power函数。 - 这一部分的单次时间复杂度为
,因为最大的 为 ,故可近似记作 。
整体时间复杂度为
空间复杂度则由递归调用的栈深度决定,为
结合题目给定的极限数据规模
Ref
- Title: 约数之和
- Author: Neurocoda
- Created at : 2026-10-05 18:30:46
- Updated at : 2026-10-05 21:01:35
- Link: https://neurocoda.com/p/2299dc9d.html
- License: This work is licensed under CC BY-ND 4.0.