题解 P1593 因子和
题目描述
给定 \(a,b\) ,求 \(a^b\) 的约数之和。
\(1\leq a,b \leq 5\times 10^7\) 。
答案对 \(9907\) 取模。
Solution
先把 \(a\) 分解质因数,假设分解后的柿子是 \(p_1^{a_1}p_2^{a_2}p_3^{a_3}\cdots\cdots p_k^{c_k}\) 。
然后 \(a^b\) 的质因数分解的柿子就是
\[p_1^{a_1\times b}p_2^{a_2\times b}p_3^{a_3\times b}\cdots\cdots p_k^{c_k\times b}
\]
根据约数求和公式,我们可以得到 \(a^b\) 的约数和是:
\[(1+p_1+p_1^2+\cdots+p_1^{a_1\times b})\times(1+p_2+p_2^2+\cdots+p_2^{a_2\times b})\times\cdots\times(1+p_k^{1}+p_k^{2}+\cdots+p_k^{c_k\times b})
\]
然后考虑如何求出 \((1+p_i+p_i^2+\cdots+p_i^{a_i\times b})\) 。
方法 1 :分治
为了更加简便,我们约定这里要求的柿子是: \((1+p+p^2+\cdots+p^k)\) 。
同时我们约定: \(f(p,k) = (1+p+p^2+\cdots+p^k)\) 。
这里分两种情况讨论:
- \(k\) 是奇数,那么原柿子可以化成:
\[(1+p+p^2+\cdots+p^\frac{k-1}{2})+(p^\frac{k+1}{2}+\cdots+p^k)\\
=f(p,\frac{k-1}{2})+p^\frac{k+1}{2}\times(1+p+p^2+\cdots+p^\frac{k-1}{2}) \\
=f(p,\frac{k-1}{2})+p^\frac{k+1}{2}\times f(p,\frac{k-1}{2}) \\
= (1 + p ^\frac{k+1}{2})\times f(p ,\frac{k-1}{2})
\]
- \(k\) 是偶数,那么我们考虑转换成奇数:
\[1+(p+p^2+\cdots+p^k) \\
=1+p\times(1+p+p^2+\cdots+p^{k-1})\\
=1+p\times f(p,k-1)
\]
注意取模。
完整代码如下
#include <cstdio>
#include <cstring>
#define int long long
const int mod = 9901;
inline int pow(int a ,int b) {
int ans = 1;
while (b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
inline int f(int p ,int k) {
if (k == 0) return 1;
if (k & 1)
return ((1 + pow(p ,(k + 1) >> 1)) % mod) * f(p ,(k - 1) >> 1) % mod;
return (1 + p * f(p ,k - 1) % mod) % mod;
}
int a ,b ,ans = 1;
signed main() {
scanf("%lld%lld" ,&a ,&b);
if (a == 0) return puts("0") ,0; //这里记得特判一下 a = 0 ,很坑
for (int i = 2;i * i <= a; i++)
if (a % i == 0) {
int s = 0;
while (a % i == 0) s++ ,a /= i;
ans = ans * f(i ,s * b) % mod;
}
if (a > 1) ans = ans * f(a ,b) % mod;
printf("%lld\n" ,ans);
return 0;
}