疯子的算法总结(一) 位运算(快速幂、快速乘)
一、預備知識(補碼,反碼)
計算機通過二進制表示整形數,比如int型32位有符號整形數:
1表示為:0000…00001(共32位)
-1表示為:1111…1111(共32位)
補碼計算法定義:非負數的補碼是其原碼本身;
負數的補碼是其絕對值的原碼最高位符號位不變,其它位取反,再加1。
表示原因:計算機邏輯運算沒有減法,-1+1最高為溢出,剩余0000000000(32位)即為0;
則有a-b=a+b的(補碼);
計算方式:
-1表示原碼為100…0001(32位),最高位位符號位。
-1的反碼表示為:1111…110(32位),除符號位按位取反。
-1的補碼表示為:1111…1111(32位),反碼+1。
正數的補碼為自己本身。
例子:
100的補碼?00000000000000000001100100?
-30的補碼 11111111111111111111111100010?
100+(-30)=000000000000000000?01000110?
轉換成10進制為70;
二、基本操作
1、按位與(&)
參加運算的兩個數,換算為二進制(0、1)后,進行與運算。只有當相應位上的數都是1時,該位才取1,否則該為為0。
將10與-10進行按位與(&)運算:
| 1111 1111 1111 0110 |
| 0000 0000 0000 0010 |
所以:10 & -10 = 0000 0000 0000 0010
2、按位或(|)
參加運算的兩個數,換算為二進制(0、1)后,進行或運算。只要相應位上存在1,那么該位就取1,均不為1,即為0。
將10與-10進行按位或(|)運算:
| 1111 1111 1111 0110 |
| 1111 1111 1111 1110 |
所以:10 | -10 = 1111 1111 1111 1110
3、按位異或(^)
參加運算的兩個數,換算為二進制(0、1)后,進行異或運算。只有當相應位上的數字不相同時,該為才取1,若相同,即為0。
將10與-10進行按位異或(^)運算:
| 1111 1111 1111 0110 |
| 1111 1111 1111 1100 |
所以:10 ^ -10 = 1111 1111 1111 1100
可以看出,任何數與0異或,結果都是其本身。利用異或還可以實現一個很好的交換算法,用于交換兩個數,算法如下:
a = a ^ b;
b = b ^ a;
a = a ^ b;
4、取反(~)
參加運算的兩個數,換算為二進制(0、1)后,進行取反運算。每個位上都取相反值,1變成0,0變成1。
對10進行取反(~)運算:
| 1111 1111 1111 0101 |
所以:~10 = 1111 1111 1111 0101
5、左移(<<)
參加運算的兩個數,換算為二進制(0、1)后,進行左移運算,用來將一個數各二進制位全部向左移動若干位。
對10左移2位(就相當于在右邊加2個0):
| 0000 0000 0010 1000 |
所以:10 << 2 = 0000 0000 0010 1000 = 40
注意,觀察可以發現,左移一位的結果就是原值乘2,左移兩位的結果就是原值乘4。
6、右移(>>)
參加運算的兩個數,換算為二進制(0、1)后,進行右移運算,用來將一個數各二進制位全部向右移動若干位。
對10右移2位(就相當于在左邊加2個0):
| 0000 0000 0000 0010 |
所以:10 >> 2 = 0000 0000 0000 0010 = 2
注意,觀察可以發現,右移一位的結果就是原值除2,左移兩位的結果就是原值除4,注意哦,除了以后沒有小數位的,都是取整。
三、延伸操作
1.快速冪(快速模冪)
①求a^b:
②求a^b%p
int pow_mod(int a, int k,int mod) { int ans = 1%mod;while(k) {if(k &1) ans =(long long) ans*a%mod; //防止在對P取模前溢出a = (long long)a*a%mod;k >>=1; //比除法快多了}return ans;}例題:BZOJ1008
2.快速乘法
方法①
方法②:高效算法
long long quickMul(long long a,long long b,long long mod) {a%=mod;b%=mod;long long ans=0;while(b){if(b&1){ans+=a;if(ans>=mod)ans-=mod;}b>>=1;a<<=1;if(a>=mod) a-=mod;}return ans; }方法③:使用long double優化版
long long quickMul(long long a,long long b,long long mod) {a%=mod;b%=mod;long long c=(long double) a*b/mod;long long ans=a*b-c*mod;if(ans<0) ans+=mod;else if(ans>=mod) ans-=mod;return ans}在這里僅提到部分操作,在ACM學習中,還有更多的操作可以用位運算。
總結
以上是生活随笔為你收集整理的疯子的算法总结(一) 位运算(快速幂、快速乘)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 001409会涨起来吗?
- 下一篇: Photoshop 漂亮的彩色光影翅膀