在講快速冪之前,先看一道如何不用快速冪來解決的問題。
求 aba^b
ab的最後三位數表示的整數。 說明:a
ba^b
ab的含義是 「a 的 b 次方」
long
pow(
long base,
long pow)
return res %
1000
;}
這不是很簡單嗎?直接乘 b 次就行啦!刷個小聰明,我還用了 lon
glong
long
呢,嘻嘻。下面求解一下 a=3
,b
=100
a = 3,b = 100
a=3,b=
100 的答案:竟然是 0?為什麼 ? 不急,我們慢慢分析。我們很早就知道了什麼是指數。
指數:在乘方 a 中,其中的 a 叫做底數,n 叫做指數,結果叫冪。f(n
)=an
f(n)=a^n
f(n)=a
n, 隨著 n 單位長度的遞增,f(n
)f(n)
f(n)
會呈「**性」增長。乙個有趣的故事:
一張紙對折一次,厚度變成原來的2倍。再對折第二次,變為原來的2的2次方倍即4倍。以此類推,假設紙的厚度為0.1mm,則對折24次以後,長度超過1千公尺;對折39次達55000千公尺,超過地球赤道長度;對折42次達44萬千公尺,超過地球至月球的距離;對折51次達22億千公尺,超過地球至太陽的距離;對折82次為51113光年,超過銀河系半徑的長度。我們知道了,原來 3
1003^
3100
的結果太大了,資料產生了溢位,得到的結果是 0。
先了解一下取模的運算規則:
( a + b )
% c =
(( a % c )
+( b % c )
)% c
( a * b )
% c =
(( a % c )
*( b % c )
)% c //看這裡
( a – b )
% c =
(( a % c ) – ( b % c )
)% c
仔細研究一下這個運算法則,會發現多個因子連續的乘積取模的結果等於每個因子取模後的乘積再取模的結果。比如:
(a*b*c)
% d =
((a%d)
*(b%d)
*(c%d)
)% d;
原來我們也可以每次乘以 3 後立即對 1000 取模。
long
pow(
long base,
long pow)
return res;
}
應對 3
1003^
3100
這樣的小資料量,這種演算法還是可以的,嘻嘻。
如果要求 2
1000000000
2^21
0000
0000
0 次方,將需要更加高效的演算法才能滿足時限需求。
快速冪演算法的核心思想就是:把指數分成兩半,而相應的底數做平方運算。這樣不僅能把非常大的指數給不斷變小,所需要執行的迴圈次數也變小,而最後表示的結果仍然是正確的。
看一下下面的例子:
指數由 10 縮減一半變成了 5,而底數變成了原來的平方,求 3
103^
310 原本需要執行 10 次迴圈操作,求 9
59^5
95卻只需要執行 5 次迴圈操作,但是 3^ 卻等於 9
59^5
95,我們用一次(底數做平方操作)的操作減少了原本一半的計算量。
如何把指數 5 變成原來的一半,5 是乙個奇數,5 的一半是 2.5,但是我們知道,指數不能為小數,怎麼辦?我們知 同底數相乘 == 底數不變指數相加。
此時,我們發現指數又變成了乙個奇數 1,按照上面對指數為奇數的操作方法,應該抽出了乙個底數的一次方,這裡即為 65611
6561^1
6561
1,這個 65611
6561^1
6561
1 我們先單獨移出來,但是此時指數卻變成了 0,也就意味著我們無法再進行「縮指數」操作了。
9 是怎麼產生的?是不是當指數為奇數 5 時 ,此時底數為 9。那 6561 又是怎麼產生的呢?是不是當指數為奇數 1 時,此時的底數為 6561。我們發現了乙個規律:最後求出的冪結果實際上就是在變化過程中所有當指數為奇數時底數的乘積。
private
static
long
fastpow
(long base,
long pow)
else
}return res;
}
在 if 和 else **塊中有重複性的**:
if..
. pow /=
2;
把原來的偶數 pow 變為了偶數 pow。
else..
. pow -=
1;
把原來的奇數 pow 變為了偶數 pow。而 res 只做了一次乘法,base 做了 3 次。
例如當 pow 是奇數 5 時,pow
−1=4
pow -1=4
pow−1=
4,pow2
=2
\cfrac=2
2pow=
2 。而如果我們直接用 pow
2\cfrac
2pow ===5
2\cfrac
25 在整型運算中得到的結果是一樣的。
private
static
long
fastpow
(long base,
long pow)
base *= base;
pow /=2;
}return res;
}
private
static
long
fastpow
(long base,
long pow)
base *= base;
pow >>=1;
}return res;
}
涉及到取模,可以用同餘讓結果不變…
long
quick
(long b,
long p,
long m)
b = b * b % m;
p >>=1;
}return res;
}
一步一步 Sql Azure
一步一步 sql azure 1.使用 windowsazure 平台賬號登陸 2.新建sqlazure server 3.新建資料庫 4.為sql azure server 新增防火牆規則,只有將本機新增到規則裡才能從本機連線到該sqlazure server 5.連線到sql azure ser...
一步一步學cscope
告之 1,我不喜歡寫部落格 因為感覺太浪費時間 2,部落格能記住自己某階段學過的東西,而這些東西可能會很快的忘卻 所以我以後要學著在部落格上浪費時間 前言 本文件記錄了我今天 2007 11 9 下午學習cscope的一點收穫,特收錄部落格以作分享。在學習cscope過程中查閱了大量的文件,但發現適...
走一步,再走一步
時光如梭,匆匆流逝的所有,讓我再一次懂得了,人生的時光門票,在不斷的穿梭過去和未來,也任光陰的手撫摸著這個現在,有太多的好像,早已和我的過去劃開了界限,無論悲傷的過往,還是美好而快樂過的曾經,都好像已經不重要了。重要的是,走一步,再走一步。這場在歲月裡一直奔跑的故事,和那始終無法為自己畫上成功圓滿的...