九度1085解題報告(機試出這種題我死定了)

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的二進制表示
      於是就有如下的實現過程了:

  1. #define LL long long int
  2. LL exp_mod( LL x , LL y , LL n ){
  3.      LL ret=1;
  4.      while(y){
  5.              if(y&1) ret=(ret*x)%n;
  6.              x=(x*x)%n;
  7.              y=y>>1;
  8.      }
  9.      return ret;
  10. }

    程序執行次數至於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;

         至於如何取模運算參考上面剛學習的快速冪取模即可。

        實現代碼如下:

  1. #include <stdio.h>
  2. #define LL long long int
  3. LL exp_mod(LL x,LL y,LL n){
  4.     LL ret=1;
  5.     while(y){
  6.         if(y&1) ret=(ret*x)%n;
  7.         x=(x*x)%n;
  8.         y=y>>1;   
  9.     }   
  10.     return ret;
  11. }
  12.  
  13. int main(){
  14.     LL a,b,k,ans;
  15.      
  16.     while(scanf("%lld%lld%lld",&a,&b,&k)==3){
  17.         ans=exp_mod(a,b,k-1);
  18.         if(ans==0) ans=k-1;
  19.         printf("%lld\n",ans);  
  20.     }
  21.     return 0;
  22. }

-----------Amazing Mathematics

注意,當我用int時,無法ac,改爲long long才能ac,因爲兩個足夠大的數在做乘法時,很可能溢出。

數學的重要性,就不用我再說了吧,讀研的時候好好加強數學背景吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章