POJ1845 Sumdiv - 乘法逆元+快速幂A^B的约数个数和

Posted dprswdr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1845 Sumdiv - 乘法逆元+快速幂A^B的约数个数和相关的知识,希望对你有一定的参考价值。

POJ1845 Sumdiv

Sol:

约数个数和\(sumdiv=(1+p_1+p_1^2+\dots + p_1^{c_1})*\dots *(1+p_k+p_k^2+\dots + p_k^{c_k})\)
其中每一项都是一个首项为1,公比为\(p_i\)的等比数列的和,即
\(1*\frac{1-p_i^{c_{k}+1}}{1-p_i}=\frac{p_i^{c_{k}+1}-1}{p_i-1}\)
可以通过快速幂+逆元求解。

然而,当\(9901|(p_i-1)\)时,\(p_i-1 ~mod ~9901\)没有乘法逆元。但\(p_i ~mod~9901 \equiv 1 (mod ~9901)\),因此等比数列的和\(\equiv 1+1^2+\dots+1^{c_{k+1}}\equiv c_k+1\)

本题数据范围较大,乘法需要用64位整数乘法实现。

Tips:

1.若\(P|x\),则\(x ~mod~ P\)没有逆元(因为P,x不互质),但\(x+1 \equiv1(mod ~P)\)
2.数据范围较大时(long long 之间相乘),需要用到64位整数乘法。

AC CODE:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int P = 9901;
typedef long long ll;
int A,B;
int read(){
    int x=0,f=1;char ch=‘ ‘;
    while(ch>‘9‘||ch<‘0‘) {if(ch==‘-‘) f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=(x<<3)+(x<<1)+(ch^‘0‘);ch=getchar();}
    return x*f;
}
ll fmul(ll a,ll b){
    ll ans=0;
    for(;b;b>>=1){
        if(b&1) ans=(ans+a)%P;
        a=(a*2)%P;
    }
    return ans;
}
ll fpow(ll a,ll b){
    ll ans=1;
    for(;b;b>>=1){
        if(b&1) ans=(ans*a)%P;
        a=(a*a)%P;
    }
    return ans;
}
int p[20],c[20];
void get_div(int x){
    int tp=x;
    int lim=sqrt(x)+1;
    for(int i=2;i<=lim;i++){
        if(tp%i==0) p[++p[0]]=i;
        while(tp%i==0){
            tp/=i;
            c[p[0]]++;
        }
    }
    if(tp>1){
        p[++p[0]]=tp;c[p[0]]=1;
    }
}
ll cal(int x){
    if((p[x]-1)%P==0){// if p[x]-1 % 9901 = 0 -> there is no inv
        return (fmul(B,c[x])%P+1)%P;
    }
    ll ans=fmul((fpow(p[x],c[x]*B+1)-1+P)%P,fpow(p[x]-1,P-2))%P;
    return ans;
}
int main(){
    freopen("data.in","r",stdin);
    freopen("sol.out","w",stdout);
    A=read();B=read();
    if(!A) {
        printf("0");return 0;
    }
    else if(A==1){
        printf("1");return 0;
    }
    else if(B==0){
        printf("1");return 0;
    }
    get_div(A);
    ll ans=1;
    for(int i=1;i<=p[0];i++){
        ans=fmul(cal(i),ans)%P;
    }
    printf("%lld",ans);
    return 0;
}

以上是关于POJ1845 Sumdiv - 乘法逆元+快速幂A^B的约数个数和的主要内容,如果未能解决你的问题,请参考以下文章

poj 1845 Sumdiv(约数和,乘法逆元)

poj1845 Sumdiv

POJ1845 Sumdiv(求所有因数和+矩阵快速幂)

POJ 1845Sumdiv——数论 质因数 + 分治 + 快速幂

POJ1845 Sumdiv [数论,逆元]

POJ 1845-Sumdiv 数论 +快速幂&&筛素&&分解质因数&&求因数之和的模板