說實話,本來是不想學這個的,總覺得學了十幾年十進制,非要用二進制可變扭了。但是,這個好像是必須得過去的坎,總沒道理總是拖着……
然後在進入正題之前,先說一個輕鬆的話題:
昨天,上c++實驗課的時候,有一個學ACM的學長來蹭課,老師檢查作業的時候看到學長寫了一個:
#define LL long long
然後,老師就問這是什麼,學長說,因爲懶,所以……blabla
然後老師又問long long是什麼……
……
學長很耐心得跟老師解釋
(╯‵□′)╯︵┻━┻我在旁邊都聽不下去了
好了,進入正題:
先談談二進制
先看看百度百科怎麼說
二進制是計算技術中廣泛採用的一種數制。二進制數據是用0和1兩個數碼來表示的數。它的基數爲2,進位規則是“逢二進一”,借位規則是“借一當二”,由18世紀德國數理哲學大師萊布尼茲發現。當前的計算機系統使用的基本上是二進制系統,數據在計算機中主要是以補碼的形式存儲的。計算機中的二進制則是一個非常微小的開關,用“開”來表示1,“關”來表示0。
定義什麼的都不重要,主要是二進制和十進制的轉換//這個考試是會考的……
二進制轉十進制(整數)
先舉個栗子:
二進制的101如果轉化爲十進制是多少呢?
首先,要確立一個思想,也就是在計算機中,大部分都是從0開始計數→所以想知道(101)2是多少,就從右邊第一項開始標號:0,1,2;接着就是計算了(101)2=1*2^2+0*2^1+1*2^0=5(相同顏色代表其相關)
好吧,我不得不承認百度寫的還是不錯的,就截圖放上來吧
二進制轉十進制(小數)
(見截圖↑)
十進制轉二進制
若爲整數就是不停地除以二然後取餘,若爲小數就是乘以二再取整
接下來談一談有關運算
--------------------以下內容來自B站某UP主上傳的視頻-------------------
---------------------------------------以上----------------------------------------
個人認爲這個視頻已經講的很清楚了(但是時間久遠,我也不記得是哪個了,現在只有PPT還留着//其實是截圖……)
好了,做了這麼長的鋪墊
現在,我們來談談快速冪的問題
說到冪函數,當然會聯想到cmath頭文件下的函數pow(底數,指數),但是如果自己寫函數呢?
我想大多數人會跟我一樣這麼寫:
#include <iostream>
using namespace std;
int power(int a,int b)
{
int ans=1;
for(int i=1;i<=b;i++)
{
ans*=a;
}
return ans;
}
int main()
{
int a,b;
int num;
while(cin>>a>>b)
{
num=power(a,b);
cout<<num<<'\n';
}
return 0;
}
這麼寫當然沒有問題,唯一的問題就是——時間複雜度(動不動就TLE還是很絕望的),這樣寫,時間複雜度大約能達到O(n),雖然看起來也沒多大,但是使用快速冪可以把時間複雜度降到O(log₂N)。
核心代碼如下:
int power(int a,int b)
{
int r=1,base=a;
while(b!=0)
{
if(b%2) r*=base;
base*=base;
b/=2;
}
return r;
}
順便引用快速冪講解代碼很短,死記也可行,但最好還是理解一下吧,其實也很好理解,以b==11爲例,b=>1011,二進制從右向左算,但乘出來的順序是 a^(2^0)*a^(2^1)*a^(2^3),是從左向右的。我們不斷的讓base*=base目的即是累乘,以便隨時對ans做出貢獻。
其中要理解base*=base這一步:因爲 base*base==base2,下一步再乘,就是base2*base2==base4,然後同理 base4*base4=base8,由此可以做到base-->base2-->base4-->base8-->base16-->base32.......指數正是 2^i ,再看上面的例子,a¹¹= a1*a2*a8,這三項就可以完美解決了,快速冪就是這樣。
順便囉嗦一句,由於指數函數是爆炸增長的函數,所以很有可能會爆掉int的範圍,根據題意選擇 long long還是mod某個數自己看着辦。