【乘法逆元】 约数之和

传送门

题意

给定 \(A,B\),求 \(A^{B}\) 的所有约数之和,答案 \(mod 9901\)

数据范围

\(0\leq A,B\leq 5\times 10^{7}\)

题解

A分解质因数后为

\[p_1^{c_{1}}\times p_2^{c_{2}}\times \cdots p_n^{c_{n}} \]

\[A^{B}=p_1^{c_{1}\times B}\times p_2^{c_2\times B}\times \cdots p_n^{c_n\times B} \]

那么AB的约数之和就是

\[(p_1^0+p_1^1+\cdots p_1^{c_1\times B})\times (p_2^0+p_2^1+\cdots p_2^{c_2\times B})\times \cdots \times (p_n^0+p_n^1+\cdots p_n^{c_n*\times }) \]

分解质因数后对每一项等比数列求和

每一项的求和公式为:

\[\frac {1 - p_i^{c_i\times B+1}}{1-p_i} \]

\[\frac{p_i^{c_i\times B+1}-1}{p_i-1} \]

分母快速幂求得\(mod~~9901\)的值

因为9901为质数,只要\(p_{i-1}\)不是他的倍数,就互质,根据费马小定理可以求出逆元,

如果是倍数,那么\(p_i ~~mod ~~9901\)为1

所以等比数列和就是\(B\times c_i+1\)

Code

#include<bits/stdc++.h>
#define pll pair<long long,long long>
#define ll long long
using namespace std;
const int mod=9901;
pll factor[2000];
int cntf;
ll qmi(ll a,ll k){
    ll res=1;
    while(k){
        if(k&1) res=res*a%mod;
        a=a*a%mod;
        k>>=1;
    }
    return res % mod;
}
void get(ll a){
    for(ll i=2;i<=a/i;i++){
        if(a%i==0){
            int num=0;
            while(a%i==0){
                num++;
                a/=i;
            }
            factor[cntf++]={i,num};
        }
    }
    if(a>1) factor[cntf++]={a,1};
}
int main(){
    ll a,b;
    cin>>a>>b;
    if(a==0)//特判
    {
        puts("0");
        return 0;
    }
    get(a);
    ll ans=1;
    for(int i=0;i<cntf;i++){
        int p=factor[i].first;
        int n=factor[i].second;
        if((p-1)%mod ==0){
            ans=(ans%mod * (b%mod*n%mod+1)%mod)%mod;
        }
        else{
            ll x=((qmi(p,b*n+1)-1)%mod+mod)%mod;// qmi求得的结果-1后可能为负数
            ll y=qmi(p-1,mod-2);
            ans=((ans*x)%mod*y)%mod;
        }
    }
    cout<<ans<<endl;
    return 0;
}
posted @ 2021-05-09 21:17  Hyx'  阅读(107)  评论(0编辑  收藏  举报