位元
建國中學 游承曦
十進位
- 正常人使用數字的進位方式
- 遇到 \(10\) 就進位
- \(817_{(10)} = 8 \times 10^2 + 1 \times 10^1 + 7 \times 10^0\)
- \(7122_{(10)} = 7 \times 10^3 + 1 \times 10^2 + 2 \times 10^1 + 2 \times 10^0\)
二進位
- 在電腦中,每個位元只能存 \(0\) 或 \(1\)
- 一樣遇到 \(2\) 就進位
- \(1010_{(2)} = 1 \times 2^3 + 0 \times 2^2 + 1 \times 2^1 + 0 \times 2^0 = 10_{(10)}\)
十進位轉二進位
- 可以用短除法來取得 (不斷除以\(2\))
\(\to 18_{(10)} = 10010_{(2)}\)
十進位轉二進位
二進位制轉換
暖身食酢題
位元運算
- C++中的另一種運算方式、運算子
- 比十進位運算還要快 (很多)
位元運算子
- &:And 運算子
- |:Or 運算子
- ^:Xor 運算子
- ~:Not 運算子
- <<:左移運算子
- >>:右移運算子
位元運算子的優先順序很低,記得加括號使用!
& And 運算
- 若兩數同一位元皆為 \(1\),則該位元運算結果為 \(1\)
- 反之為 \(0\)
| Or 運算
- 若兩數同一位元其中有一為 \(1\),則該位元運算結果為 \(1\)
- 反之為 \(0\)
^ Xor 運算
- 若兩數同一位元不一樣,則該位元運算結果為 \(1\)
- 反之為 \(0\)
^ Xor 運算
- Xor 的符號通常使用 \(\oplus\)
- Xor 的重要性質:
- \(x \oplus 0 = x\)
- \(x \oplus x = 0\)
- \(a \oplus b \oplus b = a \oplus (b \oplus b) = a \oplus 0 = a\)
~ Not 運算
- 反轉整條位元
- 特別例子: 在C++中,~\((-1_{(10)}) = 0_{(10)}\)
<< Left Shift 左移運算
- 將整條位元向左移 \(n\) 位,後面補\(0\)
- 每左移一位等價於將原數\(\times 2\)
- \(1\) << \(n\) ?
- \(2^n\) !
*以非負整數為主
>> Right Shift 右移運算
- 將整條位元向右移 \(n\) 位
- 每右移一位等價於 \(x\) := \(\lfloor \frac{x}{2} \rfloor\) (將原數除以二並無條件捨去)
*以非負整數為主
賦值懶人寫法
- &=
- |=
- ^=
- <<=
- >>=
- 沒有~=
簡單蠣鵜
給你一個正整數 \(x\),問把 \(x\) 變成 \(x+1\) 在二進位下需要進位幾次?
Hint:
後綴 \(1\) 數量
位元運算之進位篇
Problem C. 好多燈泡
給你 \(n\) 個數字,其中只有一個數出現的次數為奇數,找出那個數?
\(n \leq 10^5, \ 0 \leq x_i\) \(\leq 2^{31}\)
\(\mathcal{O}(n)\) Hint:
Xor
2021 TOI 入營考 pA
給你 \(n\) 個數字 \(x\),你需要把他們排序好,而排序準則是先照 \(popcount(x)\) 由小到大排,若一樣則照原始順序輸出
\(n \leq 10^5, \ 0 \leq x \leq 2^{30}\)
\(popcount(x) : x\) 在二進位下有幾個 bit 為 \(1\)
Problem A 和諧的共鳴頻率
給你 \(n\) 個數 \(a_i\) 和 \(q\) 次詢問
每次詢問區間 \([a_l, ..., a_r]\) Xor 起來的值
\(n, q \leq 10^6, 0 \leq a_i \leq 10^{18}\)
Collecting Beans
桌面上有許多堆豆子和一個筒子。
現在進行一種遊戲:每次找一堆豆子,如果這堆豆子只有1個,就將它放入筒子,
如果多於一個,則將它分成盡量多而且相等的兩堆,並且把剩下的一個(如果有的話)丟掉。
重複進行許多次之後,所有的豆子要不是在筒子內就是被丟掉了。
現在,我們想要知道在遊戲中會有多少豆子被放入筒子。
\(n \leq 100; a_i \leq 10^7\)
插播:快速冪
如果要求 \(x^n\) ?
\(x\) 乘 \(n\) 次會不會太慢 ?
\(n=10^9\) ?
解法一:遞迴分治
\(x^n\)
求出 \(x^{\lfloor \frac{n}{2} \rfloor}\) 後再平方就是 \(x^n\),
若 \(n\) 是奇數,再乘上一次 \(x\) 就好了!
複雜度 \(\mathcal{O}(\log n)\)
\(x^{\lfloor \frac{n}{2} \rfloor}\)
\(x^{\lfloor \frac{n}{2} \rfloor}\)
int64_t power(int64_t x, int64_t n){
if(n == 0) return 1;
if(n == 1) return x;
int64_t res = power(x, n / 2);
res = res * res;
if(n % 2 == 1) res *= x;
return res;
}
解法二:迭代快速冪
\(x^n = x^1 \times x^2 \times x^4 \times x^8 \times x^{16} \times ...\)
e.g. \(3^{19} = (1 \times 3^1) \times (1 \times 3^2) \times (0 \times 3^4) \times (0 \times 3^8) \times (1 \times 3^{16})\)
一邊做 \(3\) 的自乘一邊算答案!
\(\because 19_{(10)} = 10011_{(2)}\)
int64_t power(int64_t x, int64_t n){
int64_t res = 1;
while(n > 0){
if(n % 2 == 1) res *= x;
x *= x;
n /= 2;
}
return res;
}
int64_t power(int64_t x, int64_t n){
int64_t res = 1;
while(n){
if(n & 1) res *= x;
x *= x;
n >>= 1;
}
return res;
}
蠻噁的位元運算寫法
簡單乘法
求 \(a \times b \bmod m\)
\(0 \leq a, b \leq 10^{18}, \ 1 \leq m \leq 10^{18}\)
盡量不要用 python :p
枚舉子集合
一個簡單的題目:
給你 \(n \leq 20\) 個數字,
問你有沒有辦法選一些數字使其總和為 \(k\) ?
考慮一個純粹暴力的解法:
枚舉每一個數要選或不要選
數學上的集合
- 集合為一個包含多個元素的群聚體
- 如果有兩個集合 \(A, S\),且 \(A \subseteq S\),則 \(A\) 為 \(S\) 的子集合
- e.g.
- \(S = \{1, 2, 3, 4, 5\}\)
- \(A = \{2, 4\}\)
- 我們可以用一個整數 \(n\) 的二進位來表示一個集合的狀態
- 一個 \(n\) 個元素的集合有 \(2^n\) 個子集合 (含空集合\(\phi\))
以二進位表示集合
- 用 \(n\) 個位元的布林值來表示集合 \(S\) 的狀態
- 第 \(i\) 個位元為 \(1\) 代表 \(a_i \in S\)
- 在 \(n \leq 20 \) 時適用一個非負整數來表示一個集合
- 在 dp (動態規劃) 裡常作為 狀態壓縮 的工具
栗子
-
\(n = 19_{(10)} = 10011_{(2)}\)
-
則 \(S = \{a_0, a_1, a_4\}\)
-
\(\mid S \mid = 3\)
集合的運算 (以 int 為例)
-
有兩個集合 \(A, B\)
-
\(A \land B : A \& B\)
-
\(A \lor B : A \mid B\)
-
判斷第 \(i\) 個元素是不是在集合 \(A\) 裡: A & (1<<i) 或 (A >> i) & 1
-
包含所有元素的集合: (1<<n)-1
回到剛剛的問題
- 定義宇集 \(S = \{a_i \mid 0 \leq i < n\}\)
- 枚舉 \(S\) 的所有子集合,計算該集合內所有元素的和
- 只要有一總和為 \(k\) 就是 Yes,反之 No
枚舉子集合的寫法
int n, a[20];
int k;
bool found = false;
for(int s=1 ; s<(1<<n) ; ++s){
int sum = 0;
for(int i=0 ; i<n ; ++i){
if(s & (1<<i)){
sum += a[i];
}
}
if(sum == k){
found = true;
}
}
Rejudge!
小複雜的枚舉子集題目
毒瘤的東西
- #include <algorithm>
- __lg(x) : \(\lfloor \log_2 x \rfloor\)
- __builtin_popcount(x) : \(x\) 在二進位下 bit 為 \(1\) 的數量
- __builtin_clz(x)
更多更多的題
Logical Expression
Rock and Lever
給你 \(n\) 個數 \(a_i\),
問有幾組 \((i, j)\) 符合 \(i < j\) 且 \(a_i \& a_j \geq a_i \oplus a_j\) ?
\(n \leq 10^5\)
Apollo versus Pan
給你 \(n\) 個數 \(x_i\),
求 \(\displaystyle \sum_{i=1}^n \sum_{j=1}^n \sum_{k=1}^n (x_i \& x_j) \cdot (x_j \mid x_k)\) ?
\(n \leq 5 \times 10^5\)
Genius's Gambit
給你 \(a, b, k\)
構造兩個 0-1 字串 \(x, y\) 各有 \(a\) 個 0 和 \(b\) 個 1 (不能有前綴 0)
且 \(x-y\) 有 \(k\) 個 1
\(0 \leq a; 1 \leq b; 0 \leq k \leq a+b \leq 2 \times 10^5\)
位元DP
旅行者_九國遊歷記<4> 小綠去焱國
C-Game
鍊金術
位元
By youou
位元
- 371