约数之和
题意:假设现在有两个自然数 $A$和$B$,$S$ 是 $A^B$ 的所有约数之和。求$S$ mod $9901$的值。
前置知识
由唯一分解定理可得:一个数可以表达成$ A = {p_{1}}^{k_{1}}\times {p_{2}}^{k_{2}}\times {p_{3}}^{k_{3}}\times...\times {p_{n}}^{k_{n}} $的形式。$p_i$为不同的质数。
$A$的每个约数都可以看作从上式的每一项中抽取了特定个数($0$~$k_i$个)的$p_i$,最后乘在一起得到的。
设某约数是从第一项中选了$cnt1$个,第二项中选了$cnt2$个,... ,第$n$项中选了$cntn$个得到的,那么该约数可以表达为:$p_1 ^ {cnt1} * p_2 ^ {cnt2} ... * p_n ^ {cntn}$;
特别的,当 $cnt1$ = $cnt2$ = ... = $cntn$ = 0时,约数表示为1。
两个重要的公式
-
约数个数
$$ \left ( k_{1}+1 \right )\times \left ( k_{2}+1 \right )\times \left ( k_{3}+1 \right )\times ...\times\left ( k_{n}+1 \right ) $$
对每一项$p_i$而言,可以的选择的个数为 $0$ ~ $k_i$个,一共$k_i$ + $1$种,所以总共有($k_1$ + $1$) * ($k_2$ + $1$) * ... * ($k_n$ + $1$)种选择,即约数的个数。
只要选择稍有不同,得到的约数就不一样,不会重复,也不会遗漏。
-
约数之和
$$ \left ( p_{1}^{0} + p_{1}^{1} + p_{1}^{2} +...+ p_{1}^{k - 1} + p_{1}^{k} \right ) \times \left ( p_{2}^{0} + p_{2}^{1} + p_{2}^{2} +...+ p_{2}^{k - 1} + p_{2}^{k} \right ) \times ...\times \left ( p_{n}^{0} + p_{n}^{1} + p_{n}^{2} +...+ p_{n}^{k - 1} + p_{n}^{k} \right ) $$
为什么上面这个式子可以表示约数的和呢,因为将这个式子每一项展开之后可以得到每一项因子,加起来便为约数和。所以求解约数和就变成了求解括号内的每一个通项。
定义一个函数$sum(p, k)$,用来求解每一项$ \left ( p_{i}^{0} + p_{i}^{1} + p_{i}^{2} +...+ p_{i}^{k - 1} + p_{i}^{k} \right ) $;
这个式子的求解可以使用递归,在时间复杂度$O(logn)$的情况下求出每一项和,下面是推导过程:
- 如果k是奇数,即该式子有偶数项,那么如下:
$$\begin{split} p^{0} + p^{1} + p^{2} +...+ p^{k - 1} + p^{k} &= \left ( p^{0}+ p^{1} + ... + p^{\frac{k}{2}} \right ) + \left ( p^{\frac{k}{2}+ 1} +p^{\frac{k}{2}+ 2}+...+ p^{k}\right )\\ &= \left ( p^{0}+ p^{1} + ... + p^{\frac{k}{2}} \right )+ \left ( p^{\frac{k}{2}+ 1}\times \left ( p^{0}+ p^{1} + ... + p^{\frac{k}{2}}\right ) \right )\\ &= \left ( p^{0}+ p^{1} + ... + p^{\frac{k}{2}} \right )\times \left ( 1+ p^{\frac{k}{2}+ 1}\right ) \end{split}$$
问题的规模就从$sum(p, k)$转换成了$sum(p, \frac{k}{2})$,递归即可求得;
同时,观察推导式,我们还需要用快速幂求出$p^{(\frac{k}{2} + 1)}$。
- 如果k是偶数,有奇数项,那么先套用公式计算出$p^0 + p^1 + p^2 + ... + p^{(k - 1)}$,即$sum(p, k - 1)$,然后将算出的数乘$p$,即是$p^1 + p^2 + ... + p^k$的值,然后加上$p^0$ ,即1,得解。
#include<bits/stdc++.h>
using namespace std;
#define ll long
const int mod = 9901;
//对于有取模操作的数,x = x * x % mod;
ll getmi(int x, int k) {
x %= mod;
ll res = 1;
while (k) {
if (k & 1) res = (res * x) % mod;
x = (x * x) % mod;
k >>= 1;
}
return res;
}
ll sum(int p, int k) {
if (k == 0) return 1;
if (k & 1) {
return (1 + getmi(p, k / 2 + 1)) * sum(p, k / 2) % mod;
} else {
return (1 + p % mod * sum(p, k - 1)) % mod;
}
}
int main() {
int a, b;
cin >> a >> b;
ll ans = 1;
for (int i = 2; i <= a; i ++) {
int k = 0;
while (a % i == 0) {
k ++;
a /= i;
}
ans = ans * sum(i, k * b) % mod;
}
if (!a) ans = 0;
cout << ans << "\n";
return 0;
}

浙公网安备 33010602011771号