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

POJ 1845 Sumdiv 【逆元】

时间:2016-07-31 15:47:11      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:

题意:求A^B的所有因子之和

很容易知道,先把技术分享分解得到技术分享,那么得到技术分享,那么技术分享

     的所有因子和的表达式如下

 

    技术分享

第一种做法是分治求等比数列的和

 用递归二分求等比数列1+pi+pi^2+pi^3+...+pi^n:

(1)若n为奇数,一共有偶数项,则:
      1 + p + p^2 + p^3 +...+ p^n

      = (1+p^(n/2+1)) + p * (1+p^(n/2+1)) +...+ p^(n/2) * (1+p^(n/2+1))
      = (1 + p + p^2 +...+ p^(n/2)) * (1 + p^(n/2+1))

(2)若n为偶数,一共有奇数项,则:
      1 + p + p^2 + p^3 +...+ p^n

      = (1+p^(n/2+1)) + p * (1+p^(n/2+1)) +...+ p^(n/2-1) * (1+p^(n/2+1)) + p^(n/2)
      = (1 + p + p^2 +...+ p^(n/2-1)) * (1+p^(n/2+1)) + p^(n/2);

其他用到的知识是素数筛选以及快速幂,本博客都有相应知识或者百度也行

#include<stdio.h>
#include<string.h>
typedef long long ll;
const int mod=9901;
const int N=1e5+11;
int p[N],pr[N],cnt;
void init(){
    for(int i=2;i<N;i++){
        if(!p[i])    pr[++cnt]=i;
        for(int j=1;j<=cnt&&i*pr[j]<N;j++){
            p[i*pr[j]]=1;
            if(i%pr[j]==0)    break;
        }
    }
}
ll pow_m(ll a,ll b,ll m){
    ll ans=1;a%=m;
    while(b){
        if(b&1)
            ans=(ans*a)%m;
        a=(a*a)%m;
        b>>=1;
    }
    return ans;
}
ll sum(ll p,ll n){
    if(!n)    return 1;
    if(n&1){
        return (sum(p,n/2)*(1+pow_m(p,n/2+1,mod)))%mod;
    }
    else{
        return (sum(p,n/2-1)*(1+pow_m(p,n/2+1,mod))+pow_m(p,n/2,mod))%mod;
    }
} 
int main(){
    ll a,b;
    init();
    while(~scanf("%lld%lld",&a,&b)){
        ll ans=1;
        for(int i=1;i<=cnt&&pr[i]*pr[i]<=a;i++){
            if(a%pr[i]==0){
                int num=0;
                while(a%pr[i]==0){
                    num++;
                    a/=pr[i];
                }
                ans=(ans*sum(pr[i],num*b))%mod;
            }
        }
        if(a>1){
            ans=(ans*sum(a,b))%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

第二种方法就是用等比数列求和公式,但是要用逆元。用如下公式即可(已知a|b)

 

                     技术分享

我们来证明它,已知技术分享,证明步骤如下

 

          技术分享

在快速幂时的乘法会爆longlong,所以用快速乘

#include<stdio.h>
#include<string.h>
typedef long long ll;
const int mod=9901;
const int N=1e5+11;
int p[N],pr[N],cnt;
void init(){
    for(int i=2;i<N;i++){
        if(!p[i])    pr[++cnt]=i;
        for(int j=1;j<=cnt&&i*pr[j]<N;j++){
            p[i*pr[j]]=1;
            if(i%pr[j]==0)    break;
        }
    }
}
ll mul(ll a,ll b,ll m){
    ll ans=0;a%=m;
    while(b){
        if(b&1)
            ans=(ans+a)%m;
        a=(a+a)%m;
        b>>=1;
    }
    return ans;
}
ll pow_m(ll a,ll b,ll m){
    ll ans=1;a%=m;
    while(b){
        if(b&1)
            ans=mul(ans,a,m);
        a=mul(a,a,m);
        b>>=1;
    }
    return ans;
}
int main(){
    ll a,b;
    init();
    while(~scanf("%lld%lld",&a,&b)){
        ll ans=1;
        for(int i=1;i<=cnt&&pr[i]*pr[i]<=a;i++){
            if(a%pr[i]==0){
                int num=0;
                while(a%pr[i]==0){
                    num++;
                    a/=pr[i];
                }
                ll M=(pr[i]-1)*mod;
                ans*=(pow_m(pr[i],num*b+1,M)+M-1)/(pr[i]-1);
                ans%=mod;
            }
        }
        if(a>1){
            ll M=(a-1)*mod;
            ans*=(pow_m(a,b+1,M)+M-1)/(a-1);
            ans%=mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 http://blog.csdn.net/lyy289065406/article/details/6648539

http://blog.csdn.net/acdreamers/article/details/8220787

POJ 1845 Sumdiv 【逆元】

标签:

原文地址:http://www.cnblogs.com/L-King/p/5723108.html

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