# Kiểm tra bài vở
[TOC]
## I. Implementation Fundamentals
### I.1 – Statements (Câu lệnh)
### I.1-a: Single Statement
Một câu lệnh kết thúc bằng ;
vd:
`int x;`
`cin >> x;`
`cout << x;`
### I.1-b: Compound Statement {...}
Nhiều câu lệnh gói trong {} (block).
```
if (x > 0) {
cout << "True";
x--;
}
```
### I.1-c: if else – Rẽ nhánh.
```cpp
if (a > b) cout << "a";
else cout << "b";
```
### I.1-d: switch case – So sánh nhiều giá trị của 1 biến.
```cpp
switch (n) {
case 1: cout << "One";
break;
case 2: cout << "Two";
break;
default: cout << "Other";
}
```
### I.1-e: ternary operator – Toán tử 3 ngôi, viết gọn if else.
`int val = (a < b ? a : b);`
### I.1-f: while – Vòng lặp khi điều kiện còn đúng.
```cpp
while (n > 0) {
cout << n;
n--; }
```
### I.1-g: do while – Luôn chạy ít nhất 1 lần.
```cpp
do { cout << n; n--; }
while (n > 0);
```
### I.1-h: for – Lặp với bộ đếm.
```cpp
for (int i = 0; i < 5; i++) cout << i;
```
### I.1-i: range-for – Lặp qua container.
```cpp
vector<int> v = {1,2,3};
for (int x : v) cout << x;
```
### I.1-j: continue
Bỏ qua phần còn lại của vòng lặp, chuyển sang lần lặp tiếp.
### I.1-k: break
Thoát khỏi vòng lặp.
### I.1-l: goto
Nhảy tới nhãn(ít dùng)
### I.2 - Int Types(kiểu số nguyên)
Kiểu số nguyên cơ bản.
Theo chuẩn C++: kích thước ít nhất 16 bit (≥2 byte), nhưng trong hầu hết các hệ thống hiện đại nó là 32 bit (4 byte).
### I.2-a: int (>=2 byte)
-2,147,483,648 -> 2,147,483,647 (nếu 32-bit)
### I.2-b: unsigned int
Giống int nhưng không có số âm.
Khoảng giá trị:
0 -> 4,294,967,295 (nếu 32-bit)
Dùng khi chắc chắn giá trị luôn ≥ 0 (ví dụ: số lượng phần tử).
### I.2-c: long long
Được đảm bảo ít nhất 64 bit.
Rất phổ biến trong contest, vì int dễ bị tràn số khi xử lý giá trị lớn hơn 2e9.
Khoảng giá trị:
-9,223,372,036,854,775,808 → 9,223,372,036,854,775,807
### I.2-d: unsigned long long
Giống long long nhưng không âm
Khoảng giá trị:
0 → 18,446,744,073,709,551,615
### I.2-e: short
Ít nhất 16 bit (thường là 2 byte)
Khoảng giá trị (16-bit):
-32,768 → 32,767
### I.2-f: unsigned short
Giống short nhưng không âm
Khoảng giá trị:
0 → 65,535
### I.2-g: int8_t
đúng 8 bit (–128 → 127)
### I.2-h: int16_t
đúng 16 bit (–32,768 → 32,767)
### I.2-i: int32_t
đúng 32 bit.
### I.2-j: int64_t
đúng 64 bit.
### I.2-k: uint8_t
unsigned 8 bit (0 → 255)
### I.2-l: uint16_t
unsigned 16 bit
### I.2-m: uint32_t
unsigned 32 bit
### I.2-n: uint64_t
unsigned 64 bit
### I.2-o: size_t
Kiểu unsigned integer đặc biệt, được dùng cho kích thước hoặc chỉ số mảng/vector
Được định nghĩa trong <cstddef>
Kích thước phụ thuộc vào hệ điều hành:
32-bit OS: size_t là 32 bit
64-bit OS: size_t là 64 bit
### I.2-p: ssize_t (C++20)
Giống size_t nhưng có dấu (signed)
Dùng khi ta cần biểu diễn cả số âm trong phép tính với kích thước hoặc chỉ số
### I.3 - Float Types(kiểu số thực)
### I.3-a: float
4 byte(32 bit, có thể làm tròn đến 6-7 số thập phân)
### I.3-b: double
8 byte(64 bit, có thể làm tròn 12-13 số thập phân)
### I.3-c: long double
Kích thước ≥ 10 byte (80, 96 hoặc 128 bit tùy máy)
Độ chính xác cao hơn double.
### I.4 - Char & String Types(Ký tự và chuỗi)
### I.4-a: char
Kiểu cơ bản, 1 byte (8 bit).
Thường lưu 1 ký tự ASCII (‘a’, ‘A’, ‘1’, ‘*’...)
### I.4-b: signed char
signed char: giá trị từ –128 → 127
### I.4-c: unsigned char
unsigned char: 0 → 255.
### I.4-d: string
Kiểu chuỗi động của STL
có nhiều hàm: a.size(), a.substr(), a.find()
### I.4-e: string_view
Cho phép “nhìn” vào chuỗi mà không copy dữ liệu
### I.4-f: fstream
Đọc file
### I.4-g: ifstream
Ghi file
### I.4-h: ofstream
Đọc và ghi
### I.4-i: stringstream
Cho phép gán giá trị chuỗi như stream
### I.4-j: istringstream
Cho phép xử lý chuỗi như stream (dùng >>)
### I.4-k: ostringstream
Cho phép xử lý chuỗi như stream (dùng <<)
### I.4-l: char8_t (C++20)
Dùng để lưu ký tự trong Unicode.
char8_t: UTF-8 (1 byte/ký tự).
### I.4-m: char16_t
char16_t: UTF-16 (2 byte).
### I.4-n: char32_t
char32_t: UTF-32 (4 byte).
### I.4-o: istream
Nhập chuẩn
### I.4-p: ostream
Xuất chuẩn
### I.4-q: cin
Nhập từ bàn phím
### I.4-r: cout
in ra màn hình
### I.4-s: cerr
In lỗi
### I.4-t: clog
In log
### I.4-u: Escape Character ('\n', '\\', '\'', '\"', ...)
Escape character: ký tự đặc biệt bắt đầu bằng \
'\n' : xuống dòng.
'\t' : tab.
'\\': in dấu \.
'\"': in dấu ".
### I.4-v: Escape Sequence ('\nnn', '\o{nnn}', '\xnnn', '\x{nnn}', ...)
Escape sequence: dạng số/mã:
'\x41' = 'A' (theo hệ 16).
'\101' = 'A' (theo hệ 8).
### I.6 - Literals (Hằng số trong code)
### Kiểu số nguyên:
### I.6-a: Long Literal (1L)
1L = long
### I.6-b: Unsigned Long Literal (1U)
1U = unsigned
### I.6-c: Long Long Literal (1LL)
1LL = long long
### I.6-d: Unsigned Long Long Literal (1ULL)
1ULL = unsigned long long
### Hệ cơ số:
### I.6-f: Signed Size Literal (1Z) (C++23)
1Z = size_t
### I.6-g: Octal Literal (0123)
0123 = octal(hệ 8)
### I.6-h: Hex Literal (0x123)
0x123 = hex(hệ 16)
### I.6-i: Binary Literal (0b123)
0a1010 = binary(hệ nhị phân)
### Hệ số thực:
### I.6-j: Float Literal (.1f)
.1f = float
### I.6-k: Double Literal (.1)
.1 = double
### I.6-l: Long Double Literal (.1L)
.1L = long double
### Ký tự/Chuỗi:
### I.6-m: Char Literal ('\n')
'a' = ký tự
### I.6-m: String Literal ("abc")
"abc" = chuỗi
### I.6-m: Raw String Literal (R"(raw\nstring)")
R"(raw\nstring)" = raw string (không xử lý \n)
### I.6-z: Digit Separator (123'456'789)
int x = 123'456'789; = 123456789
### I.7 - Cast(ép dữ liệu)
### I.7-a: C Cast (Type)(Data)
double x = 3.14;
int y = (int)x;
cout << y;
y = 3
### con trỏ:
void* p = &x;
double* dp = (double*)p;
### I.7-b: Static Cast static_cast<Type>(Data)
```cpp
double x = 5.8;
int y = static_cast<int>(x);
y = 5
```
### con trỏ:
```cpp
void* p = &x;
double* dp = static_cast<double*>(p);
```
### I.8 - Scoping
### I.9-
### I.10 – Unary Operators (Toán tử đơn ngôi)
### I.10-a: +x (Unary Plus)
Giữ nguyên giá trị của x, chỉ thể hiện rõ ràng là số dương
### I.10-b: -X Unary Minus
Đổi dấu giá trị của x
### I.10-c: !X Negation
Phủ định logic(not)
### I.10-d: ~X Bitwise NOT(Đảo bit)
Đảo tất cả các bit của số nguyên x
Vd:
```
int x = 5; // 5 = 00000101 (8-bit)
int y = ~x; // đảo hết → 11111010
cout << y; // in ra 250 (nếu 8-bit)
```
### I.10-e: ++X Pre Increment
Tăng x lên 1 rồi trả về giá trị mới vừa +
### I.10-f: --X Pre Decrement
Giảm x xuống 1 rồi trả về giá trị mới -
### I.10-g: X++ Post Increment
Trả về giá trị cũ rồi mới tăng x
### I.10-h: X-- Post Decrement
Trả về giá trị cũ rồi mới giảm x
### I.11 - Arithmetic Operators(Toán tử số học)
### I.11-a: A+B Addition Plus
Cộng
### I.11-b: A-B Subtraction Minus
Trừ
### I.11-c: A*B Multiplication Multiply
Nhân
### I.11-d: A/B Division Div
Chia
### I.11-e: A%B Remainder Mod
Chia lấy dư(Modulo)
### I.12 - Comparison Operators(Toán tử so sánh)
### I.12-a: A<B Less LE
Nhỏ hơn
### I.12-b: A<=B Less Or Equal LEQ
Nhỏ hơn hoặc bằng
### I.12-c: A>B Greater GE
Lớn hơn
### I.12-d: A>=B Greater Or Equal GEQ
Lớn hơn hoặc bằng
### I.12-e: A==B Equal EQ
Bằng
### I.12-f: A!=B Not Equal NEQ
Không Bằng
### I.12-g: A<=>B Three-way Spaceship Operator
Dùng để so sánh 3 chiều: nhỏ hơn, bằng, lớn hơn trong 1 phép
### I.13 - Logic Operators(Toán tử logic)
### I.13-a: A&&B Logic And
Trả true nếu cả 2 điều kiện đều đúng
### I.13-b: A||B Logic Or
Trả true nếu ít nhất 1 điều kiện đúng
### I.13-c: There is no Logic Xor Operator
bool x = (A != B);
### I.13-d: Short Circuit
Trình biên dịch ngừng kiểm tra sớm nếu đã biết kết quả
### I.14 - Bitwise Operators(Toán tử Bit)
### I.14-a: A<<B Shift Left
Dịch tất cả các bit của A sang trái B lần
Mỗi lần dịch trái tương đương nhân với 2^B
Vd:
```
int x = 3; // 00000011
int y = x << 2; // 00001100 = 12
```
## BONUS:P
### I.14-b: A >> B – Shift Right (Dịch phải)
Dịch toàn bộ bit của A sang trái B lần
Các bit mới bên phải được điền bằng 0
### I.14-c: A & B – Bitwise AND
Chỉ trả về 1 khi cả hai bit đều 1, ngược lại là 0
Ví dụ:
A = `00001101` (13)
B = `00001010` (10)
A & B = `00001000` (8)
### I.14-d: A | B – Bitwise OR
Trả về 1 nếu ít nhất một bit bằng 1
Ví dụ:
A = `00001101` (13)
B = `00001010` (10)
A | B = `00001111` (15)
### I.14-e: A ^ B – Bitwise XOR (Exclusive OR)
Trả về 1 nếu 2 bit khác nhau, ngược lại 0
Ví dụ:
A = `00001101` (13)
B = `00001010` (10)
A ^ B = `00000111` (7)
### I.14-f: ~A – Bitwise NOT (Đảo bit)
Đảo tất cả các bit: 1 -> 0, 0 -> 1
Vd:
A = `00001101` (13)
~A = `11110010` (tùy số bit, ví dụ 8-bit -> 242)
**II. Implementation**
-
**II.1-a:** **`IsZero(X)`**
Chuyển số x sang chuỗi nhị phân. Dùng phép `&` với x và một chuỗi toàn số 0. Nếu `x != 0` thì phép `&` sẽ trả về một chuỗi có bit khác 0.
```cpp
int isZero (int x) {
if (x == 0) {
return true;
}
else {
return false;
}
}
```
**II.1-b:** `IsOdd(X)` `IsEven(X)`
```cpp
bool isOdd(int n) {
return n & 1;
}
bool isEven(int n) {
return !(n & 1);
}
```
**II.1-c:** `IsPowerOfTwo(X)`
Một số $n$ có giá trị bằng $2^k$ thì khi biểu diễn dưới dạng nhị phân chỉ có đúng 1 bit bật và còn lại là bit tắt.
Suy ra $n-1 = 2 ^ {k-1}$. Số $2 ^ {k-1}$ sẽ có $k-1$ bit bật, vì vậy dùng phép toán `&` với số này, nếu $n$ có đúng 1 bit bật thì trả về kết quả sẽ là 0 (False), còn nếu ngược lại thì kết quả trả về sẽ là 1 (True).
```cpp
#include <iostream>
using namespace std;
bool IsPowerOfTwo(int x) {
return x > 0 && (x & (x - 1)) == 0;
}
int main() {
int n; cin >> n;
if(Ispoweroftwo(n)) cout << "YES";
else cout << "NO";
return 0;
}
```
**II.1-d:** `IsPowerOfFour(X)`
Số là lũy thừa của 4 nếu:
Nó là lũy thừa của 2 (IsPowerOfTwo(x))
Bit 1 duy nhất nằm ở vị trí chẵn
-> 0x55555555 (binary 0101...) chỉ có bit ở vị trí chẵn = 1
=> (x & 0x55555555) kiểm tra xem bit 1 của x nằm ở chỗ chẵn
```cpp=
#include <iostream>
using namespace std;
bool IsPowerOfFour(int x){
return x > 0;
&& (x & (x - 1)) == 0
&& (x & 0x55555555);
}
int main(){
int n; cin >> n;
if(IsPowerOfFour(n)) cout << "YES";
else cout << "NO";
}
```
### **II.1-e:** `CheckBit(X, B)` `SetBit(X, B)` `UnsetBit(X, B)` `ToggleBit(X, B)`
```cpp
bool checkbit(int x, int b) {
return (n & (1 << k));
}
```
```cpp
int togglebit (int x, int b) {
return n ^= (1 << k);
}
```
```cpp
int unsetbit (int x, int b) {
return n &= ~(1 << k);
}
```
```cpp
int setbit (int n, int k) {
return n |= (1 << k).
}
```
### **II.1-f** `AssignBit(X, B, V)`
Gán bit thứ B của X = giá trị V(0 hoặc 1)
```cpp
int assignbit(int x,int b,int v) {
if(v != 0 && v != 1){
return x;
}
return (x & (~1 << B)) | (V << B)
}
int main(){
int B, V, X; cin >> X >> B >> V
x = assignbit(X, B, V);
cout << bitset<8>(x);
}
```
### **II.1-g:** `ToBinary(X)` `ToOctet(X)` `ToHex(X)`
```cpp
string tobinary(int x) {
bitset<32> b(x);
return b.to_string();
}
```
```cpp
void tooctet(int x) {
cout << oct << x;
}
```
```cpp
void tohex (int x) {
cout << hex << x;
}
```
### II.1-i
```cpp
void xorswap(int x, int y) {
x = x ^ y;
y = x ^ y;
x = x ^ y;
cout << x << " " << y;
}
```
### II.1-j
```cpp
int length(int n) {
int cnt = 0;
while (n > 0) {
n /= 2;
cnt++;
}
return cnt;
}
```
```cpp
double log2 (int x) {
long double l = log(x);
return l;
}
```
### II.1-k
```cpp
int countsetbit (int x) {
int cnt = 0;
while (x > 0) {
if (x & 1 == 1) {
cnt++;
}
x >>= 1;
}
return cnt;
}
```
```cpp
int countunsetbit (int x) {
int cnt = 0;
while (x > 0) {
if (x & 1 == 0) {
cnt++;
}
x >>= 1;
}
return cnt;
}
```
### II.1-l
```cpp
int CountTrailingZero (int x) {
int cnt = 0;
while (x > 0) {
if (x & 1 == 0) {
cnt++;
x >>= 1;
}
else {
break;
}
}
return cnt;
}
```
### II.1-m
```cpp
int CountTrailingOne (int x) {
int cnt = 0;
while (x > 0) {
if (x & 1 == 1) {
cnt++;
x >>= 1;
}
else {
break;
}
}
return cnt;
}
```
```cpp
int CountLeadingZero (int x) {
int cnt = 0;
for (int i = 31; i >= 0; i--) {
if (((x >> i) & 1) == 0) {
cnt++;
}
else {
break;
}
}
return cnt;
}
```