http://ac.jobdu.com/problem.php?pid=1085
我自己的方法是構造bigint數據類型,然後無腦循環乘求冪,然後再轉換k進制,遞歸求解。這種做法的時間複雜度就不用說了,數據稍微一大一定超時。真正有效的做法代碼很簡單,卻需要很強的數學知識和嚴格證明,自知達不到這個水平,果斷引來大神的博客http://blog.sina.com.cn/s/blog_8619a25801010wcy.html快速冪取模。原文如下:
計算x^ymod n;如果採用常規方法,當x與y都比較小的情況下,採用直接計算可以,但是如果當x跟y都非常大的時候,如2^1000mod 100000,那該如何解決呢?
利用模運算的這個:(a*b)mod
n = ((a mod n) * b ) mod n;
例如:2^11
mod 100 = 2^(1011) mod 100= ((2 ^(1010)mod 100)*2)mod 100……
1011爲11的二進制表示
於是就有如下的實現過程了:
- #define LL long long int
- LL exp_mod( LL x , LL y , LL n ){
- LL ret=1;
- while(y){
- if(y&1) ret=(ret*x)%n;
- x=(x*x)%n;
- y=y>>1;
- }
- return ret;
- }
程序執行次數至於y的位長度有關。
實戰例子:求root(N, k)
2010年清華的上機題目,題意請點擊題目處鏈接。
本題可以有如下分析:
N=a0+a1*k+a2*k^2+……+an*k^n;
N'=a0+a1+a2+……+an;
N-N'=a1*(k-1)+a2*(k^2-1)+……+an*(k^n-1);
提取(k-1)有: (N-N')%(K-1)=0;
繼續遞推下去有: (N-N')%(k-1) =0;
(N'-N'')%(k-1)=0;
……
(N(r-1)-N(r))%(k-1)=0;
相加有:(N-N(r))%(k-1)=0,N(r)是我們要求的結果,故有
N(r) = N % (k-1);
如果 N(r)==0 ,爲邊界,則 N(r) = k-1;
至於如何取模運算參考上面剛學習的快速冪取模即可。
實現代碼如下:
-
#include <stdio.h>
-
#define LL long long int
-
LL exp_mod(LL x,LL y,LL n){
-
LL ret=1;
-
while
(y){
-
if
(y&1) ret=(ret*x)%n;
-
x=(x*x)%n;
-
y=y>>1;
-
}
-
return
ret;
-
}
-
int
main(){
-
LL a,b,k,ans;
-
-
while
(
scanf
(
"%lld%lld%lld"
,&a,&b,&k)==3){
-
ans=exp_mod(a,b,k-1);
-
if
(ans==0) ans=k-1;
-
printf
(
"%lld\n"
,ans);
-
}
-
return
0;
-
}
-----------Amazing Mathematics
注意,當我用int時,無法ac,改爲long long才能ac,因爲兩個足夠大的數在做乘法時,很可能溢出。數學的重要性,就不用我再說了吧,讀研的時候好好加強數學背景吧。