题解 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;
}
posted @ 2021-04-18 12:15  recollector  阅读(59)  评论(0编辑  收藏  举报