题目链接: 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 |
时间: 2024-11-10 16:21:58