目录
题目解析
这是一个非常经典的数论题目,考察了 唯一分解定理 (Prime Factorization)、约数和公式 (Sum of Divisors) 以及 同余运算 (Modular Arithmetic) 的综合应用。
1. 核心数学原理
第一步:唯一分解定理
任意一个大于 1 的整数
那么,
第二步:约数和公式
对于一个数
对应到我们的题目,令
第三步:等比数列求和
每一项
根据求和公式:
我们需要计算这个结果对
2. 难点与特殊情况处理
我们需要计算
这里分为两种情况:
- 情况 A:
不是 的倍数 - 也就是说
。 - 因为
是一个质数(你可以写个小程序验证一下,或者相信题目),我们可以使用 费马小定理 求逆元。 的逆元为 。 - 公式变为:
。
- 也就是说
- 情况 B:
是 的倍数 - 也就是说
。 - 此时不能使用除法公式(分母为 0)。
- 但是回到原始的求和式子:
。 - 因为
,所以每一项都变成了 1。 - 一共有
项。 - 结果直接为
。
- 也就是说
3. 算法流程
- 特判:如果
,输出 0;如果 ,输出 1。 - 质因数分解:对
进行质因数分解,得到所有的 。 - 计算每一部分:对于每个质因子
,计算等比数列的和,并累乘到答案中。 - 输出:最终结果。
4. AC 代码 (C++)sum_of_factors.cpp12月31日 23:18
5. 代码解析与易错点
- 取模的时机:
- 在快速幂
qpow内部,base一开始就要取模。 - 在计算分子
numerator时,减法可能会导致负数,所以必须写成(a - b + MOD) % MOD。
- 在快速幂
- 逆元存在的条件:
- 一定要特判
(p % MOD) == 1的情况。如果不特判,分母p-1模9901为 0,求逆元会得到错误结果或者除零错误。 - 注意是
p % MOD == 1,不是p == 1。比如时,它模 9901 也是 1。
- 一定要特判
- 数据范围:
最大 。 - 分解质因数只循环到
,速度非常快。 - 指数部分
可能会超过 int范围,所以涉及指数的变量最好开long long。
的情况: - 虽然题目约定
,但如果 能取 0,要特判。如果 ,没有因子和(或者说由定义决定),通常输出 0。 时, ,因子和为 1。
- 虽然题目约定
代码
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github : https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* date: 2026-01-01 09:16:32
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e6+5;
const int mod = 9901;
int n,m;
ll a,b;
//快速幂
ll quick_pow(ll base,ll exp) {
ll res = 1;
for( ; exp ; exp >>= 1 )
{
//是1就乘
if( exp & 1) res = (res * base ) % mod;
// base 增增
base = (base * base) %mod;
}
return res;
}
// 计算等比数列前 n+1 项和: 1 + p + ... + p^n
// 公式: (p^(n+1) - 1) / (p - 1)
ll _sum(ll p, ll n) {
if( (p % mod) == 1 ) {
return (n+1) % mod;
}
ll num = (quick_pow(p,n+1) - 1 +mod) %mod;
ll fen_mu = (p-1) %mod;
//求逆元
ll inv = quick_pow(fen_mu, mod-2);
return (num * inv) % mod;
}
signed main () {
ios::sync_with_stdio(false); cin.tie(0);
std::cin >> a >> b;
if( a == 0)
{
std::cout << 0 << "\n";
return 0;
}
if (b== 0) {
std::cout << 1 << "\n";
return 0;
}
ll ans = 1;
// 分解质因数
for(int i = 2 ; i*i <= a; ++i)
{
if( a % i == 0)
{
ll cnt = 0;
while( a % i == 0) cnt++ ,a /=i;
// 我们需要计算 1 + p + ... + p^(count*B)
ll sum_ans = _sum(i, cnt * b);
ans *= sum_ans;
ans %= mod;
}
}
//剩余部分
if( a > 1) {
ll sum_ans = _sum(a, b);
ans *= sum_ans;
ans %= mod;
}
std::cout << ans << "\n";
return 0;
}