约数和公式证明:
pk^ak 的约数为:1 , pk , pk^2 , pk^3 , ... ,pk^ak
实际上n的约数是在p0^a0、p1^a1、p2^a2、...、pk^ak每一个的约数中分别挑一个相乘得来
所以它们的和为 :
s(n)=(p0^0+p0^1+p0^2+…p0^a0)(p1^0+p1^1+p1^2+…p1^a1)(p2^0+p2^1+p2^2+…p2^a2)…(pk^0+pk^1+pk^2+…pk^ak)
容易理解,若gcd(a,b)=1 ,则 s(a*b) = s(a) * s(b)
看: hdu1452 Happy 2004
计算因子和 s(2004^X) mod 29 ,
2004=2^2 *3 *167
2004^X=2^2X * 3^X *167^X
s(2004^X) ) = s(2^2X) * s(3^X) * s(167^X)
= (2^0+2^1+2^2+...+2^2x) * (3^0+3^1+3^2+...+3^x) * (167^0+167^1+167^2+...+167^x)
= (2^0+2^1+2^2+...+2^2x) * (3^0+3^1+3^2+...+3^x) * (22^0+22^1+22^2+...+22^x) ................. 有(167%29=22)
= (2^(2X+1)-1) * ((3^(X+1)-1)/2) * ((22^(X+1)-1)/21)
怎么算(a/b)%p ? 设 (a/b)%p = y;
a/b = k*p + y ;
a = k*p*b + y*b ;
因为p>y,则p*b > y*b
所以 y*b = a % (p*b)
所以 (a/b)%p = y = a%(p*b) / b
#include<cstdio> #include<cmath> using namespace std; int quick(int a,int b,int m){ //a^b%m int ans = 1,tmp = a; while(b){ if(b&1) { ans*=tmp; ans%=m; } tmp*=tmp; //低级错误,这里不应该是tmp*=a tmp%=m; b>>=1; } return ans; } int main(){ int x,a1,a2,a3; while(scanf("%d",&x)!=EOF&&x){ a1 = quick(2,2*x+1,29)-1; if(a1<0) a1+=29; a2 = quick(3,x+1,2*29)-1; if(a2<0) a2+=2*29; a2/=2; a3 = quick(22,x+1,21*29)-1; if(a3<0) a3+=21*29; a3/=21; printf("%d\n",a1*a2*a3%29); } }
%运算法则 1. (a*b) %p= ( a%p) *(b%p)
%运算法则 2. (a/b) %p= ( a *b^(-1)%p) 除法的
s(2004^X)=(2^(2X+1)-1)* (3^(X+1)-1)/2 *(22^(X+1)-1)/21
(a*b)/c %M= a%M* b%M * inv(c)
c*inv(c)=1 %M 模为1的所有数 inv(c)为最小可以被c整除的
inv(2)=15, inv(21)=18 2*15=1 mod 29, 18*21=1 mod 29
s(2004^X)=((2^(2X+1)-1)* (3^(X+1)-1)/2 *(22^(X+1)-1)/21)mod 29
=((2^(2X+1)-1)* (3^(X+1)-1)*15 *(22^(X+1)-1)*18)mod29
b^(-1)是 b的逆元素(%p)即上面的inv
2的逆元素是15 ,因为2*15=30 % 29=1 % 29
21的逆元素是18 ,因为21*18=378% 29 =1 % 29
因此
a=(powi(2,2*x+1,29)-1)% 29;
b=(powi(3,x+1,29)-1)*15 % 29;
c=(powi(22,x+1,29)-1)*18 % 29;
ans=(a*b)% 29*c % 29;