1. 程式人生 > >HDU 1452 Happy 2004

HDU 1452 Happy 2004

在ACM中,數學題很多,數學也是相當重要的。本題就要用到數學知識,真是書到用時方恨少,大家還是多記數學定理和結論吧。

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

分析一下,本題求的是2004^x的約數和對29取模,這裡我們要計算,約數和,下面介紹兩個定理:

①整數唯一分解定理:

一個整數A一定能被分成:A=(P1^K1)*(P2^K2)*(P3^K3).....*(Pn^Kn)的形式。其中Pn為素數。

如2004=(22)*3*167。

那麼2004x=(22x)*(3x)*(167x)。

②約數和公式

對於一個已經被分解的整數A=(P1^K1)*(P2^K2)*(P3^K3).....*(Pn^Kn),

有約數和S=(1+P12+P13+.....P1k1)*.....(1+Pn2+Pn3+.....Pn

kn)。

(1+P12+P13+.....P1k1)是一個等比數列,化簡為(P1k1+1 -1)/(P1-1).

對於2004^X, 只要求出a=pow(2,2*x+1)-1,b=pow(3,x+1)-1,c=pow(167,x+1)-1即可,使用快速冪取模計算。

所以我們要算的是(a*b/2*c/166)%29,那麼裡面這個除法怎麼處理呢,方法就是取乘法逆元,也就是說令e=2*166%29=9,則(a*b/2*c/166)%29=(a*b*c*e)%29。

下面是程式碼:

#include<cstdio>
#define ll long long
const int mod=29;
ll quickpow(ll a,ll b){
	ll ans=1;
	a=a%mod;
	while(b){
		if(b&1) ans=ans*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return ans;
}
int main()
{
	ll x;
	while(~scanf("%lld",&x)&&x){
		ll a=quickpow(2,2*x+1)-1;
		ll b=quickpow(3,x+1)-1;
		ll c=quickpow(167,x+1)-1;
		printf("%lld\n",(a*b*c*9)%mod);
	}
 } 

當然,在網上查的時候看有的兄弟找出了規律做,在下實在佩服,可以參考:點選開啟連結

可能有的人不理解上面的除法(a*b/2*c/166)%29=(a*b*c*e)%29取模,其實這也是個推出來的結論,記憶就行了:

(因為這裡a、b、c是取模後的結果,所以不能拿他們直接除2*166,但是如果不取模可以除,但是太大了一定會溢位)

當我們要求(a / b) mod p的值,且 a 很大,無法直接求得a / b的值時,我們就要用到乘法逆元。
滿足 b * k ≡ 1 (mod p) 的 k 的值就是 b 關於 p 的乘法逆元。

我們可以通過求 b 關於 p 的乘法逆元 k,將 a 乘上 k 再模 p,即 (a * k) mod p。其結果與(a / b) mod p等價

(可以用擴充套件歐幾里得)

在下實力有限,歡迎大家指出錯誤,謝謝。