分解 A 得 σ(A^B)=∏(1+p+…+p^{eB}),等比和用倍增递推求,只靠乘加不碰逆元,避开 p≡1 (mod 9901) 时 p-1 不可逆的陷阱。
OJ: roj
题目 ID: 1633
难度:普及+/提高-
标签:数学数论约数和快速幂python
创建: 2026-09-30 23:43
更新: 2026-10-07 13:50
形式化题目
给定整数
即设
样例:
正解
思路
一句话本质:先分解
第一步:把约数和拆成等比级数。
记
朴素做法:对每个质因子写一个循环,逐项累加
问题? 等比数列求和有现成公式
这正是本题唯一的陷阱。
| 真值 |
除法公式 |
||
|---|---|---|---|
第二步:倍增递推求等比和。
把
问题? 这两个式子为什么成立?
奇数情形
偶数情形
以
| 调用 | 形态 | 展开 | 结果 |
|---|---|---|---|
| 基础 |
验证:
flowchart TD
A["S(p, n)"] -->|"n=0"| B["返回 1"]
A -->|"n 为奇数<br/>n = 2m+1"| C["S(p,m) × (1 + p^(m+1))"]
A -->|"n 为偶数<br/>n = 2m"| D["S(p,m-1) × (1 + p^m) + p^(2m)"]
C --> A
D --> A
每层 pow(p, k, 9901) 快速幂,每层
第三步:合并与边界。
各质因子的
或 : ,唯一约数是 ,输出 (真实测点 即为 )。 : ,约定输出 。 : ,输出 。
分解时试除到
代码
factorize 返回 geometric 即上面的 solve 把两者相乘得到
Python 版:
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 23:43
# update_at: 2026-09-30 23:43
import sys
MOD = 9901 # 模数,且是素数;但 p≡1 (mod 9901) 时 p-1 不可逆,故不能用除法公式求等比和
def geometric(p: int, n: int) -> int:
"""求 1+p+...+p^n (mod MOD),倍增法:只用乘加,不碰逆元。"""
if n == 0:
return 1 % MOD
m = n >> 1
if n & 1: # n = 2m+1:S(n) = S(m) * (1 + p^(m+1))
return geometric(p, m) * (1 + pow(p, m + 1, MOD)) % MOD
# n = 2m:S(n) = S(m-1) * (1 + p^m) + p^(2m)
return (geometric(p, m - 1) * (1 + pow(p, m, MOD)) + pow(p, 2 * m, MOD)) % MOD
def factorize(a: int) -> dict[int, int]:
"""试除分解 a,返回 {质因子: 指数}。"""
factors: dict[int, int] = {}
d = 2
while d * d <= a:
while a % d == 0:
factors[d] = factors.get(d, 0) + 1
a //= d
d += 1
if a > 1: # 残留的是大于 sqrt(原 a) 的素因子,指数必为 1
factors[a] = factors.get(a, 0) + 1
return factors
def solve() -> None:
A, B = map(int, sys.stdin.buffer.read().split())
if B == 0 or A == 1: # A^B = 1,唯一的约数是 1
print(1)
return
if A == 0: # 0 的正整数次幂是 0
print(0)
return
ans = 1
for p, e in factorize(A).items():
ans = ans * geometric(p, e * B) % MOD
print(ans)
if __name__ == "__main__":
solve()C++ 版(同一算法):
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 23:30
* update_at: 2026-10-05 23:30
*/
// main.cpp:求 A^B 的所有正约数之和 mod 9901。
// 关键点:A^B 的约数和 = ∏(1+p+...+p^{eB});等比和用倍增递推求,
// 只靠乘加,避开 p≡1 (mod 9901) 时 p-1 不可逆、除法公式失效的陷阱。
#include <cstdio>
using namespace std;
typedef long long ll;
const ll MOD = 9901; // 题目模数(素数,但 p-1 未必可逆,不能依赖除法公式)
ll A, B;
// 快速幂:返回 base^exp mod MOD
ll power_mod(ll base, ll exp) {
ll res = 1;
base %= MOD;
while (exp > 0) {
if (exp & 1) {
res = res * base % MOD;
}
base = base * base % MOD;
exp >>= 1;
}
return res;
}
// 倍增法求等比和 S(p,n)=1+p+...+p^n (mod MOD),只用乘加
ll geometric(ll p, ll n) {
if (n == 0) {
return 1 % MOD;
}
ll m = n >> 1;
if (n & 1) {
// n = 2m+1:S(n) = S(m) * (1 + p^{m+1})
return geometric(p, m) * (1 + power_mod(p, m + 1)) % MOD;
}
// n = 2m:S(n) = S(m-1) * (1 + p^m) + p^{2m}
return (geometric(p, m - 1) * (1 + power_mod(p, m)) + power_mod(p, 2 * m)) % MOD;
}
void solve() {
scanf("%lld %lld", &A, &B);
if (B == 0 || A == 1) { // A^B = 1,唯一约数是 1
printf("1\n");
return;
}
if (A == 0) { // 0 的正整数次幂是 0
printf("0\n");
return;
}
ll ans = 1;
ll rest = A; // 剩余待分解部分
for (ll d = 2; d * d <= rest; d++) {
if (rest % d != 0) {
continue;
}
ll e = 0; // 质因子 d 的指数
while (rest % d == 0) {
rest /= d;
e++;
}
ans = ans * geometric(d, e * B) % MOD;
}
if (rest > 1) { // 残留的是大于 sqrt(A) 的素因子,指数必为 1
ans = ans * geometric(rest, B) % MOD;
}
printf("%lld\n", ans);
}
int main() {
solve();
return 0;
}复杂度
- 时间复杂度:分解
次试除( 时约 次);每个质因子 , ,合计 。 ,递归深度不超过 层。 - 空间复杂度:
(不计递归栈;栈深 )。 - 实测 20 组真实数据全部通过,单点约
s、峰值内存 MB,相对 ms / MB 很宽裕。
总结
本题的骨架是约数和公式: