数论初步(费马小定理) - Happy 2004
Description
Consider a positive integer X,and let S be the sum of all positive integer divisors of 2004^X. Your job is to determine S modulo 29 (the rest of the division of S by 29).
Take X = 1 for an example. The positive integer divisors of 2004^1 are 1, 2, 3, 4, 6, 12, 167, 334, 501, 668, 1002 and 2004. Therefore S = 4704 and S modulo 29 is equal to 6.
Input
The input consists of several test cases. Each test case contains a line with the integer X (1 <= X <= 10000000).
A test case of X = 0 indicates the end of input, and should not be processed.
Output
For each test case, in a separate line, please output the result of S modulo 29.
Sample Input
1
10000
0
Sample Output
6
10
-----------------------------------------------------------------我是分割线^_^--------------------------------------------------------------------------------
这个题的题目倒是挺happy的,做题的我一点都不happy,我一直在想这都什么方法,毕竟水太深了,我也溺水了= =
老样子,先解释题目:题目的意思就是给定一个X,要求求出2004的X次方的因数和,因数和嘛,比如4的因数和就是
1 + 2 + 4 = 7,然后呢,题目的意思就是这样,然偶我就懵比了,懵比了很久搜题解去了,搜到了还是懵比,什么鬼题解,
就不能说详细一点吗,详细一点的打字又不准确,不理解的部分有那么多.............算了不吐槽了= =
先来一条科普:费马小定理,
费马小定理(Fermat Theory)是数论中的一个重要定理,其内容为: 假如p是质数,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p)。
即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。
结合一下同余德定理,a^(p - 1)%p = 1%p = 1,也就是说,在一些情况下可以把1替换成前面那个东西,等一下有用。
看着题目当然没头绪,直接来方法吧,我们先把2004分解质因数,得到了2,3,167,这些东西有什么用呢?下面再来看看一个新东西
一个数的因子和是一个积性函数
关于积性函数,即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这四个数,
这就是所谓的一个数的因子和是一个积性函数。
则题目求为:S(2004^X)mod 29
那么可以知道:2004=4 * 3 *167(注意到4不是质数,但使用要求必须是质数,所以要替换成2的平方)
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),这个表达式的意思是求p的x次方的这个数的因数和
所以:S(2004^X) % 29 = (2^(2X+1)-1) % 29 * (3^(X+1)-1)/2 % 29 * (167^(X+1)-1)/166 % 29,
因为答案是要对29取模的,所以前面一项可以动用快速幂取模算出来了,可是后面两个带有除法就有点难搞了,
在乘法中可以a*b%c = (a%c * b%c)%c, 加法中也可以有(a+b+c)%c = (a+(b+c)%c)%c,减法也是有的,和加法一样,
可惜的是除法是个奇葩,它非主流= =,所以不能这样这样算,不信的话你算一算(14/2)%4,你换成(14%4) / (2%4)答案
是不一样的,这个时候就要用到一种叫做逆元的东西,它的作用是把除法改成乘法取模,比如a/b % c 可以改成 a * b^(c-2)%c,
其中b^(c-2)%c就是b的逆元,这只是逆元的一种求解方法,由于结合了费马小定理,这种方法比较适合于计算机,因为可以用快速幂
取模进行运算求解,现在来开始变化:a/b % c = a * b^(-1) % c = a * b^(-1) * 1 % c,然后倒回去看上面的费马小定理的下面
那一条小提示,就可以把1替换了,结果变成了a * b^(-1) * b^(c-1) % c = a * b^(c-2) % c,好的,如此一来就顺利完成的转换,
除法的取模也变成的乘法,接下来就可以使用快速幂取模进行大屠杀了,不过写代码的时候要注意减一(等比数列求和)..........
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
using namespace std;
int Mod(int a, int b, int c) {//快速幂取模算出a的b次方模c的结果
int ans = 1;
while (b) {
if (b & 1) {
ans = ans * a % c;
}
b >>= 1;
a = a * a % c;
}
return ans;
}
int main()//如果看n有点不习惯,就按照上面的习惯看,把n换成x就行了
{
//freopen("input.txt", "r", stdin);
int n;
while (scanf("%d", &n), n) {
int a = Mod(2, 2 * n + 1, 29) - 1;//求S(a)
int b = (Mod(3, n + 1, 29) - 1) * Mod(2, 27, 29);//求S(b)
int c = (Mod(22, n + 1, 29) - 1) * Mod(21, 27, 29);//这里把167换成了22,是因为22与167对29是同余的,所以简化一下,求S(c)
printf("%d\n", a * b * c % 29);//这里就是答案,S(答案) = S(a) * S(b) * S(c),还不理解就上去看看奇性函数= =
}
return 0;
}