码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-10-10 00:58:50      阅读:145      评论:0      收藏:0      [点我收藏+]

标签:快速   实现   include   ==   turn   ring   read   HERE   stdin   

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的约数个数和】

标签:快速   实现   include   ==   turn   ring   read   HERE   stdin   

原文地址:https://www.cnblogs.com/Loi-Brilliant/p/9763923.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!