poj 1845 二分

题意:求A^B的所有因数的和 (0 <= A,B <= 50000000), 结果对9901取余。

分析:设A=p1^r1*p2^r2*...*pn^rn,则A^B=p1^(B*r1) * p2^(B*r2) * ... * pn^(B*rn)。

A^B的因数之和为:(1+p1+p1^2+...+p1^(B*r1)) * (1+p2+p2^2+...+p2^(B*r2)) *... * (1+pn+pn^2+...+pn^(B*rn));

等比数列求和公式:(p^n-1) / (p-1)     p-1可能为9901的倍数,即gcd(p-1,9901) !=1,不能用逆元。

也不能用公式a/b%m = a%(bm)/b,因为bm容易越界。

令f(n)=1+p+p^2+...+p^n,

n为奇数时,f(n) = (1+p+p^2+...+p^(n/2)) * (1 + p^(n/2+1)) = f(n/2) * (1 + p^(n/2+1)),

n为偶数时,f(n) = f(n-1) + p^n。

可以递归求解

 

 

int mod = 9901;
int a, b, s;

int pri[]={2,3,5,7,11,13,17....7079};

LL modexp(int a, int b)     {
    LL ans = 1; LL t = a;
    while(b) {
       if(b & 1) ans = ans * t % mod;
       t = t * t % mod;
       b >>= 1;
    }
    return ans;
}

int cal(int p, int n){//计算1+p+p^2+...+p^n
    if(!n) return 1;
    if(n&1) return cal(p, n/2)*(1+modexp(p, n/2+1)) % mod;
    else return (cal(p, n-1) + modexp(p, n)) % mod;
}

void solve(int n){
    s = 1;
    for(int i = 0; pri[i] * pri[i] <= n; i++){
        int cnt = 0;
        while(n % pri[i] == 0) {//找到质因子
            n /= pri[i];
            cnt++;
        }
        if(cnt) s = s * cal(pri[i],cnt*b) % mod;
    }
    if(n > 1) s = s * cal(n,b) % mod;
}

int main(){
    #ifndef ONLINE_JUDGE
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    #endif

    cin>>a>>b;
    if(!a){cout<<0<<endl;return 0;}

    solve(a);
    cout<<s<<endl;

    return 0;
}

 

posted @ 2013-05-18 15:44  心向往之  阅读(166)  评论(0编辑  收藏  举报