杭电 1452 Happy 2004

题目地址: 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;
}




数论学过,也忘的差不多了,还得多多练习啊。


你可能感兴趣的:(杭电,happy,2004,1452)