HDU 1452 (约数和+乘法逆元)

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1452

题目大意:求2004^X所有约数和,结果mod 29。

解题思路

①整数唯一分解定理:

一个整数A一定能被分成:A=(P1^K1)*(P2^K2)*(P3^K3).....*(Pn^Kn)的形式。其中Pn为素数。

如2004=(22)*3*167。

那么2004x=(22x)*(3x)*(167x)。

②约数和公式

对于一个已经被分解的整数A=(P1^K1)*(P2^K2)*(P3^K3).....*(Pn^Kn),

有约数和S=(1+P12+P13+.....P1k1)*.....(1+Pn2+Pn3+.....Pnkn)。

(1+P12+P13+.....P1k1)是一个等比数列,化简为(P1k1+1 -1)/(P1-1).

对于2004^X, 只要求出a=pow(2,2*x+1)-1,b=pow(3,x+1)-1,c=pow(167,x+1)-1即可,使用快速幂计算,注意快速幂模板里要mod。

关键问题在于ans=(a*b/2*c/166) mod 29的计算问题,因为除法是不能同余计算的,所以要计算2*166关于29的乘法逆元,转化成乘法取模。

所以ans=(a*b*c*rev) mod 29。

#include "cstdio"

#define LL long long

#define mod 29

LL ex_gcd(LL a,LL b,LL &x,LL &y)

{

    if(a==0&&b==0) return -1;

    if(b==0) {x=1;y=0;return a;}

    LL d=ex_gcd(b,a%b,y,x);

    y-=a/b*x;

    return d;

}

LL mod_reverse(LL a,LL n)

{

    LL x,y,d=ex_gcd(a,n,x,y);

    if(d==1) return (x%n+n)%n;

    else return -1;

}

LL pow(LL a,LL n)

{

    LL base=a,ret=1;

    while(n)

    {

        if(n&1) ret=(ret*base)%mod;

        base=(base*base)%mod;

        n>>=1;

    }

    return ret%mod;

}

int main()

{

    LL T,x;

    while(scanf("%I64d",&x)!=EOF&&x)

    {

        LL a=pow(2,2*x+1)-1,b=pow(3,x+1)-1,c=pow(167,x+1)-1,rev=mod_reverse(2*166,mod);

        printf("%I64d\n",(a*b*c*rev)%mod);

    }

}

 

12170066 2014-11-13 11:02:46 Accepted 1452 0MS 228K 734 B C++ Physcal

 

 

 

你可能感兴趣的:(HDU)