POJ 1845 Sumdiv(求因数和 + 逆元)题解

题意:给你a,b,要求给出a^b的因子和取模9901的结果。

思路:求因子和的方法:任意A = p1^a1 * p2^a2 ....pn^an,则因子和为sum =(1 + p1 + p1^2 + ... . + p1^a1)*(1 + p2 + p2^2 + ... . + p2^a2)*(1 + pn + pn^2 + .... + pn^an)。又由等比数列求和公式可知 1 + pn + pn^2 + .... + pn^an =(pn^an - 1)/(pn - 1)。因为要mod 9901,所以除数取模要用到逆元:A / B mod m = (A mod(B * m))/ B。在快速幂求解过程中会爆过程,所以手动写了乘法。

参考:逆元详解   【逆元】

补充:

任意A = p1^a1 * p2^a2 ....pn^an

因数和:sum =(1 + p1 + p1^2 + ... . + p1^a1)*(1 + p2 + p2^2 + ... . + p2^a2)*(1 + pn + pn^2 + ... . + pn^an)

因数个数:num = (a1 + 1)*(a2 + 1)....(an + 1)

代码:

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 20000 + 10;
const int seed = 131;
const int MOD = 9901;
const int INF = 0x3f3f3f3f;
ll mul(ll a, ll b, ll c){
    ll ans = 0;
    while(b){
        if(b & 1){
            ans = ans + a;
            if(ans > c) ans -= c;
        }
        a = a + a;
        if(a > c) a -= c;
        b >>= 1;
    }
    return ans;
}
ll pmul(ll a, ll b, ll c){
    a = a % c;
    ll ans = 1;
    while(b){
        if(b & 1) ans = mul(ans, a, c);
        a = mul(a, a, c);
        b >>= 1;
    }
    return ans;
}
int main(){
    ll a, b;
    while(~scanf("%lld%lld", &a, &b)){
        ll ans = 1;
        for(ll i = 2; i * i <= a; i++){
            if(a % i == 0){
                ll num = 0;
                while(a % i == 0){
                    a /= i;
                    num++;
                }
                ans *= (pmul(i, b * num + 1, (i - 1) * MOD) - 1) / (i - 1);
                ans %= MOD;
            }
        }
        if(a > 1){
            ans *= (pmul(a, b + 1, (a - 1) * MOD) - 1) / (a - 1);
            ans %= MOD;
        }
        printf("%lld
", ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/KirinSB/p/9562365.html