標籤:
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)就是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;}
數論初步(費馬小定理) - Happy 2004