题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=1452
题目大意是让你求2004的X次方的所有因子之和。
很明显遇到所谓的求什么因子啦,倍数啥的一般都是用数论问题解决。
一个数的因子和是一个积性函数
关于积性函数,即F(ab)=F(a)*F(b),在数论里有很多积性函数
来证明一下:
S(x)表示x的因子和。
如果x可以分成a,b(一定为素数),那么S(x)=S(a)*S(b)。
为什么一定要分成素数呢,因为一个素数的因子之后1和它本身,对于a,b 来说,就是1,a,1,b,那么x=a*b,x的因子只有1,a,,b,x这四个数,
(1+a)*(1+b)=1+a+b+a*b。看明白了么,这就是所谓的一个数的因子和是一个积性函数。
则题目求为:S(2004^X)mod 29
那么可以知道:2004=4 * 3 *167
S(2004^X)=S(2^(2X)) * S(3^X) * S(167^X)
如果 p 是素数 则其因子只有1和它本身,S(p^X)=1+p+p^2+...+p^X = (p^(X+1)-1)/(p-1)
所以:S(2004^X)=(2^(2X+1)-1) * (3^(X+1)-1)/2 * (167^(X+1)-1)/166
考虑到 167%29 == 22
原式可写为 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)
其中inv(c)即满足 (c*inv(c))%M=1的最小整数,用术语讲,inv(c)表示c在模p下的乘法逆元
这里M=29 则inv(1)=1,inv(2)=15,inv(22)=15
原式可写为: S(2004^X)=(2^(2X+1)-1) * (3^(X+1)-1)/2 * (22^(X+1)-1)/21
=(2^(2X+1)-1) * (3^(X+1)-1)*15 * (22^(X+1)-1)*18
进一步15*18%29=9;
所以就是求 : (2^(2X+1)-1) * (3^(X+1)-1)* (22^(X+1)-1)*9%29;
代码如下:
#include <cstdio> using namespace std; //求a的b次方 int power(int a,int b){ int res=1; while (b) { if (b&1) res = res*a%29; a = a*a%29; b>>=1; } --res; return res<0 ? res+29 : res; } int main(){ int x,a,b; while (~scanf("%d", &x)&& x){ a = (2*x+1)%28; //2的a次方 b = (x+1)%28; //3的b次方 printf("%d\n", 9 * power(2,a) * power(3,b) * power(22,b) % 29 ); } return 0; }
数论学过,也忘的差不多了,还得多多练习啊。