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

 

 

 

posted @ 2014-11-13 11:33  Physcal  阅读(549)  评论(0编辑  收藏  举报