對於演算法競賽來說,演算法的效率自然是很重要的。有些時候我們可以使用一切巧妙地辦法借助資料本身的特點進行處理。比如今天這個題。
問題描述
給定l,r
。統計[l,r]
區間內的所有數在二進位制下包含的「1」的個數之和。如5的二進位制為101
,包含2個「1」。
輸入格式
第一行包含2個數l,r
輸出格式
乙個數s,表示[l,r]
區間內的所有數在二進位制下包含的「1」的個數之和。
樣例輸入
2 3
樣例輸出
3
資料規模和約定
l<=r<=100000;
進製,即進製計數制,是人為定義的一種帶進製的計數方法,便於使用有限的數字字元表示所有的數。對於任何一種進製都表示某一位置上的數字達到某一值後向上進一位。如常用的十進位制計算9+1
時,當個位數字9增加1時,應該變為十,但是我們採用十進位制計數,所以在這一位上並不會出現表示十的數字,而是向上進製變為10
。同理,對於8進製而言,當計算7+1
時,並不出現8
這個數字,而是變為10
,而這個8進製的10
與十進位制的8
是相等的。也可以發現,進製的轉換並不會改變量值本身的大小,只是表示方法的改變。
進製的轉換通常可以使用連續做除法取餘數的方式,如十進位制數6
轉二進位制可以如下方式計算:
6 ÷2
=3......0
6 ÷2 = 3 ...... 0
6÷2=3.
....
.03 ÷2
=1......1
3 ÷2 = 1 ...... 1
3÷2=1.
....
.11 ÷2
=0......1
1 ÷2 = 0 ...... 1
1÷2=0.
....
.1將餘數從下往上倒過來即是相應進製,即6的二進位制表示為110
。
因為在進製轉換的過程中數值大小本身並不變化,所以人工計算時對於不方便計算的數值也可以通過轉換為其他進製作為媒介來進行。
對於該題目來說,我們可以將過程分為幾步:
迴圈[l,r]
之間所有整數
將整數表示為二進位制
通過變數計數二進位制數中1的個數
有以下程式框架
#include
intmain
(void
)
使用for迴圈[l,r]
之間所有整數
#include
intmain
(void
)printf
("%d"
, count)
;return0;
}
將整數表示為二進位制的方法在上面已經講到,在計算機中,我們使用取模運算子%
可以直接得到餘數,然後對該整數除以2,再取餘數,直到商為0為止。
同時,第3步計數的過程可以直接與取模運算同時進行,這樣還可以節省儲存二進位制數的記憶體空間。
#include
intmain
(void
) t = t /2;
}while
(t !=0)
;}printf
("%d"
, count)
;return0;
}
這還不夠,這樣乙個簡單的題目我們並不能滿足於將其做對,而應該對其進行優化,使其效率更高。這樣在複雜問題中才能夠盡可能解決更多測試資料。
所以對於本題,我將輸入資料擴大到l<=r<=100000000;
來測試演算法效率(題目約定範圍的1,000倍)
測試,輸入資料0 100000000
輸出1314447116
用時11.98秒。
由於我們數的是二進位制中1的個數,所以在計數時我們不需要先判斷t % 2
是否等於1,可以直接讓count
變數加上t % 2
的值,如果t % 2
為1,則count
加1,若為0,則不變。
#include
intmain
(void
)while
(t !=0)
;}printf
("%d"
, count)
;return0;
}
測試輸入資料0 100000000
,輸出1314447116
,用時6.651秒。
在計算機中,由於計算機的原理所致,在計算和儲存時,實際上都是以二進位制方式進行的,每個二進位制位稱為乙個位元(bit),為了便於操作,又有每8個位元為乙個位元組(byte)。
也就是說實際上我們需要的二進位制資料在計算機中已經存在了,不需要做除法就可以獲得我們需要的資料。我們只需要將計算機記憶體中每一位的資料取出計數即可。
對於計算機中「位」的操作和運算,我們稱之為「位操作」、「位運算」。而位操作的速度相比數值運算更快,所以我們通過位操作能夠提高解題效率。本題中,我們將每一位取出的操作可以使用「移位操作」和「位與運算」。
移位操作即將記憶體中的二進位制資料向指定方向移動指定個位,如有一8位整型變數n = 53
,53
的二進位制表示為0011 0101
,對其進行向右移2位的操作語句為n >> 2;
,得到二進位制表示為0000 1101
的數13。
位與運算即將兩個數按二進位制位做與操作,對於8位整型變數n = 53
,將其和22(10)作與操作,53的二進位制表示為0011 0101
,22的二進位制表示為0001 0110
,將二者按位作與運算,可得二進位制表示為0001 0100
的數20。
那麼對於二進位制數而言,想取出其中某1位資料,只需要對其進行移位操作和位與運算,如對於n = 53
,希望取出其第4位(右數,0開始),即(n >> 4) & 1
。53的二進位制表示0011 0101
右移4位後為0000 0011
,位與0000 0001
後為0000 0001
,所以53的第4位為1.
將以上思路帶入我們的演算法
#include
intmain
(void)}
printf
("%d"
, count)
;return0;
}
測試輸入資料0 100000000
,輸出1314447116
,用時4.756秒。 二進位制 二進位制起源
現代通訊技術的基礎是二進位制編碼。早在1865年麥克斯韋總結出麥克斯韋方程組之前,美國人摩斯 morse 於1837年發明了摩斯電碼和有線電報。有線電報的出現,具有劃時代的意義 它讓人類獲得了一種全新的資訊傳遞方式,這種方式 看不見 摸不著 聽不到 完全不同於以往的信件 旗語 號角 烽火,這也是二進...
判斷二進位製半整數(二進位制)
10年後,tokitsukaze大佬已經變成了年收入超百萬的的精英程式設計師,家裡沒錢也沒礦的teitoku,找tokitsukaze大佬借1000塊錢,然後tokitsukaze大佬說,借你1024吧,湊個整數。沒錯在2進製下1024是 二進位制整數 乙個正整數滿足其值為2的k次方 k為正整數 我...
mysql二進位制 MySql二進位制連線方式詳解
使用mysql二進位制方式連線 您可以使用mysql二進位制方式進入到mysql命令提示符下來連線mysql資料庫。例項以下是從命令列中連線mysql伺服器的簡單例項 root host mysql u root p enter password 在登入成功後會出現 mysql 命令提示視窗,你可以...