# 位元運算與快速冪
## 感受一下
[MDJudge T042《C++:從入門到放棄》](http://mdcpp.mingdao.edu.tw/problem/T042)
[TOI初選 原始人排序](http://mdcpp.mingdao.edu.tw/problem/T052)
## 進位法
### 十進位
就是平常我們熟悉的數字寫法
每個位數可能是0 1 2 3 4 5 6 7 8 9其中一個
當一個位數超過9就得進位
ex) $9+1=10$
個位塞不下了
所以進位到十位
### 二進位
==電腦的世界==
每個數僅由0 1組成
$(1)_{10}=(1)_2$
$(2)_{10}=(10)_2$
### 十六進位(補充)
==計算機領域的世界==
二進位的進化版
但比起二進位更不直觀
認識就好
數字由0 1 2 3 4 5 6 7 8 9 A B C D E F所組成
\
補充python code

## 進位法換算
### 個位與十位的意義
個位 顧名思義就是那個位數數字代表的值要乘1(也就是$10^0$)
十位的數字代表的值要乘10(也就是$10^1$)
以此類推
### 二進位轉十進位
:::spoiler {state="open"}舉個栗子
$(11001)_2=(?)_{10}$
$1*2^0+0*2^1+0*2^2+1*2^3+1*2^4=25$
:::
### 十進位轉二進位
:::spoiler {state="open"}舉個栗子
$(?)_2=(25)_{10}$
$25=1*2^0+0*2^1+0*2^2+1*2^3+1*2^4$
$?=11001$
:::
## 位元運算
:::success
C++裡 int是以二進位儲存的
因此宣告int a=25;
在內部記憶體會以11001來存
這就能解釋
為什麼位元運算比其他運算快很多
以及int的範圍是2^32
:::
假設$a=(25)_{10}=(011001)_2$
以及$b=(42)_{10}=(101010)_2$
方便後面解說
### & (and)
==25 & 42 = 8==
以二進制數來比較$a,b$
若該位數皆為$1$則結果也為$1$
否則為$0$
### | (or)
==25 | 42 = 59==
以二進制數來比較$a,b$
若該位數皆為$0$則結果也為$0$
否則為$1$
### ^ (xor)
==25 ^ 42 = 51==
以二進制數來比較$a,b$
若該位數數碼相同則結果為$0$
否則為$1$
### ! (not)
$!1=0$
$!0=1$
### >> 和 << (位移運算子 不是輸出輸入)
$a$>>$n$代表$a$右移$n$個bits
即$a=[a/2^n]$
$a$<<$n$代表$a$左移$n$個bits
即$a=a*2^n$
## 快速冪
**求$123^{25}=?$**
慢慢乘?
也是可以
再快一點?
> $a^{25}=a^1*a^8*a^{16}$-------<1>
把25轉成二進制分解
數值是1就乘進去
不太明白?
把$(11001)_2$跟<1>比較一下
### code
```c++
int fpow(int a, int k){
int base = a, ans = 1;
while(k){
if(k&1)ans*=base;
base*=base;
k>>1;
}
return ans;
}
```
### 大數...?
大家都知道指數成長爆炸快
該不會求這東西都要用大數運算?
### 取模
通常這一類題目都會要你求除以某數後的餘數
所以...
[請接著服用:同餘](https://hackmd.io/O6Qm7k06TU22sajD5PN25A?both)
###### tags: `MDCPP` `Cosmos`
note:矩陣快速冪模板
```cpp=
#include<bits/stdc++.h>
#define loli ios::sync_with_stdio(0);cin.tie(0);
#define endl '\n'
#define int long long
#define mod 1000000007
using namespace std;
struct mat{
int m[101][101];
};
mat init(int n);
mat mul(mat a,mat b,int n);
mat fpow(mat a,int b,int n);
mat a,e;//a:輸入 e:單位矩陣
int n;//矩陣長度 (每行n個數 )
using namespace std;
signed main(){
loli
mat a;
int k;
cin>>k;
if(k<2)cout<<k;
else{
n=2;
a.m[0][0]=1;a.m[0][1]=1;a.m[1][0]=1;a.m[1][1]=0;
for(int i=0;i<n;i++)e.m[i][i]=1;
mat out=fpow(a,k,n);
cout<<out.m[0][1]%mod;
}
return 0;
}
mat init(int n){
mat z;
for(int i=0;i<n;i++)for(int j=0;j<n;j++)z.m[i][j]=0;
return z;
}
mat mul(mat a, mat b, int n){
mat Multi=init(n);
for(int i=0;i<n;i++){//from A第一橫排
for(int j=0;j<n;j++){//from B第一直排
for(int k=0;k<n;k++){//第k元素
Multi.m[i][j]+=a.m[i][k]*b.m[k][j];
Multi.m[i][j]%=mod;
}
}
}
return Multi;
}
mat fpow(mat a, int b, int n){
mat power=a,ans=e;
while(b){
if(b&1)ans=mul(ans,a,n);
a=mul(a,a,n);
b/=2;
}
return ans;
}
```