# OIA
## I. Implementation Fundamentals (Whats given by the C++ Language)
## Statements
### Single Statement ...;
```cpp
code(); //Single statement
```
- Một dòng lệnh kết thúc bằng dấu ;
### Compound Statement {...}
```cpp
{
code1();
code2();
codeN();
} //Compound statement
```
- Được bao bọc trong {}, có trong ```if else```, ```switch```, ...
### if else
```cpp
if(condition){
code();
}
else{
code();
}
```
- Nếu thì ... nếu không thì ...
### switch case [[fallthrough]];
```cpp!
switch(expression){
case value1:
code();
break;
case value2:
code();
[[fallthrough]]
}
```
- ```switch``` là cấu trúc điều khiển dùng để chọn một nhánh thực thi trong nhiều nhánh dựa trên giá trị
- ```[[fallthrougt]]``` là một attribute trong C++ để vô hiệu hóa cảnh báo của compiler khi không thêm break (việc này sẽ làm code bị nhảy xuống ```case``` phía dưới)
### ternary operator
```cpp!
condition ? expressionTrue : expressionFalse
```
- Toán tử ba ngôi là rút gọn của ```if-else```
### while
```cpp!
while(condition){
code();
}
```
- Thực thi một khối lệnh trong khi điều kiện đúng (kiểm tra trước, thực thi sau)
### do while
```cpp
do{
code();
}
while(condition)
```
- Thực thi một khối lệnh trong khi điều kiện đúng (thực thi trước, kiểm tra sau)
### for
```cpp
for(int a = 0; a < n ; ++a){
code();
}
```
### range-for
```cpp
vector<int> a;
for (int x : a)
{
code();
}
```
- Lặp lại số lần dựa trên kích thước của container (```a.size()```)
### continue
```cpp
if (condition){
continue; //Ignores the current condition
}
```
- Từ khóa continue trong C++ được dùng trong vòng lặp (```for```, ```while```, ```do-while```) để bỏ qua phần còn lại của lần lặp hiện tại và chuyển ngay sang lần lặp tiếp theo.
### break
- Được dùng trong switch để code bị nhảy xuống case phía dưới, cú pháp
```cpp
switch(expression){
case value1:
code();
break;
case value2:
code(); //Bị nhảy xuống case value3
case value3:
code();
break;
}
```
### goto
```cpp
goto label;
label:
code();
```
- Dùng để nhảy tới một nhãn (tức là thực thi mã trong nhãn đó)
### return ; return <expressions>;
```cpp
int a(){
return 300; //a() return 300
}
int main(){
return 0; //main() return 0
}
void b(){
//Void does not return anything
}
```
- Trả về một giá trị
### while(true) for (;;)
```cpp
while(true){
code;
}
for(;;){
code2;
}
```
- Vòng lặp vô tận
- ```while(true)``` sẽ gây cảnh báo trên một số compiler
### for (auto [u, v] : edges) (C++17)
```cpp
vector<pair<int, int>> edges = {
{1, 2},
{2, 3},
{3, 4}
};
for (auto [u, v] : edges) {
cout << u << << " " << v << '\n';
}
```
Output:
1 2
2 3
3 4
- ```range for``` với tính năng ràng buộc có cấu trúc
- Mỗi phần tử trong container phải là một struct/tuple/pair có thể lấy được giá trị được.
## Int Types
### int (≥2 byte)
- Số bit: ≥ 16 (hoặc 32) tùy máy
- Min value: −2.14e9
- Max value: 2.14e9
### unsigned int
- Số bit: ≥ 16 (hoặc 32) tùy máy
- Min value: 0
- Max value: 4.29e9
### long long
- Số bit: ≥ 64
- Min value: −9.22e18
- Max value: 9.22e18
### unsigned long long
- Số bit: ≥ 64
- Min value: 0
- Max value: 1.84e19
### short
- Số bit: ≥ 16 tùy máy
- Min value: −3.28e4
- Max value: 3.27e4
### unsigned short
- Số bit: ≥ 16 tùy máy
- Min value: 0
- Max value: 6.55e4
### int8_t
- Số bit: 8
- Min value: 0
- Max value: 1.27e2
### int16_t
- Số bit: 16
- Min value: −3.28e4
- Max value: 3.27e4
### int32_t
- Số bit: 32
- Min value: −2.14e9
- Max value: 2.14e9
### int64_t
- Số bit: 64
- Min value: −9.22e18
- Max value: 9.22e18
### uint8_t
- Số bit: 8
- Min value: 0
- Max value: 2.55e2
### uint16_t
- Số bit: 16
- Min value: 0
- Max value: 6.55e4
### uint32_t
- Số bit: 32
- Min value: 0
- Max value: 4.29e9
### uint64_t
- Số bit: 64
- Min value: 0
- Max value: 1.84e19
### size_t
- Kiểu số nguyên không dấu (unsigned) được dùng để biểu diễn kích thước của đối tượng hoặc số phần tử trong bộ nhớ.
### ssize_t (C++20)
- Kiểu số nguyên có dấu (signed) tương ứng với ```size_t``` (Có thể là số âm)
## Float Types
### float
- Số bit: 32 bit
- Số byte: 4 byte
- Độ chính xác: ≈ 6–7 chữ số
### double
- Số bit: 64 bit
- Số byte: 8 byte
- Độ chính xác: ≈ 15–16 chữ số
### long double
- Số bit: 64 bit hoặc 80 bit hoặc 128 bit tùy máy
- Số byte: 10, 12, 16 byte (Linux); 8 byte (Windows)
- Độ chính xác: ≈ 18–19 chữ số
## Char & String Types
### char
- Mô tả: Kí tự ASCII
- Số byte: 1 byte
- Phạm vi giá trị: -128 đến 127
- Ghi chú: Dùng để chứa kí tự đơn (chữ, số, một số icon)
### signed char
- Mô tả: kí tự có dấu
- Số byte: 1 byte
- Phạm vi giá trị: -128 đến 127
- Ghi chú: nó như char bình thường (nếu hệ thống mặc định char là signed char)
### unsigned char
- Mô tả: kí tự không dấu
- Số byte: 1
- Phạm vi giá trị: 0 đến 255
- Ghi chú: giống char nhưng không dấu
### string
- Mô tả: Container của các ```char```
- Thư viện: ```<string>```
- Ghi chú: Dạng động, tự quản lí bộ nhớ
- Cú pháp: ```string a = "your string here";```
### string_view
- Mô tả: ```string_view``` sẽ trỏ đến vùng nhớ của chuỗi khác (không lưu giá trị) giúp truy cập nhanh hơn
- Thư viện: ```<string_view>```
- Ghi chú: Nếu dữ liệu chuỗi trỏ đến bị thay đổi hoặc hủy, ```string_view``` sẽ trỏ đến vùng nhớ không hợp lệ
- Cú pháp: ```std::string_view view = aStringHere;```
### fstream
- Mô tả: Đọc/ghi file
- Thư viện: ```<fstream>```
- Ghi chú: Kết hợp ifstream + ofstream
### ifstream
- Mô tả: Đọc file
- Thư viện: ```<fstream>```
- Ghi chú: Input file stream
### ofstream
- Mô tả: Ghi file
- Thư viện: ```<fstream>```
- Ghi chú: Output file stream
### stringstream
- Mô tả: Đọc & ghi chuỗi trong bộ nhớ
- Thư viện: ```<sstream>```
### istringstream
- Mô tả: Đọc chuỗi (input)
- Thư viện: ```<sstream>```
### ostringstream
- Mô tả: Ghi chuỗi (output)
- Thư viện: ```<sstream>```
### Tại sao nên dùng stringstream, istringstream, ostringstream?
- Cú pháp ngắn gọn, đỡ bug
- Tiện lợi (dễ append text, ...)
- An toàn kiểu
### char8_t (C++20)
- Mô tả: kí tự UTF-8
- Số byte: 1 byte
- Phạm vi giá trị: 0 đến 255
- Ghi chú: dùng với ```u8"..."``` literal
### char16_t
- Mô tả: kí tự UTF-16
- Số byte: 2 byte
- Phạm vi giá trị: 0 đến 65'535
- Ghi chú: dùng với ```u"..."``` literal
### char32_t
- Mô tả: kí tự UTF-32
- Số byte: 4 byte
- Phạm vi giá trị: 0 đến 4,294,967,295
- Ghi chú: dùng với ```U"..."``` literal
### istream
- Mô tả: Luồng đầu vào (nhập dữ liệu)
- Thư viện: ```<ostream>```
### ostream
- Mô tả: Luồng đầu ra (xuất dữ liệu)
- Thư viện: ```<ostream>```
### cin
- Kiểu: std::istream
- Mô tả: lấy dữ liệu được nhập từ phím
### cout
- Kiểu: std::ostream
- Mô tả: xuất dữ liệu ra console
### cerr
- Kiểu: std::ostream
- Mô tả: Xuất lỗi (không buffer)
### clog
- Kiểu: std::ostream
- Mô tả: Xuất log (có buffer)
### Escape Character ('\n', '\\', '\'', '\"', ...)
- Escape character là ký tự đặc biệt dùng để báo hiệu rằng ký tự kế tiếp có ý nghĩa đặc biệt, chứ không được hiểu theo nghĩa thông thường.
- Trong C/C++, escape character là dấu gạch chéo ngược ```\```
### Escape Sequence ('\nnn', '\o{nnn}', '\xnnn', '\x{nnn}', ...)
- Escape sequence là toàn bộ cặp (hoặc chuỗi) gồm escape character \ + ký tự (hoặc số) phía sau, tạo nên một ký tự đặc biệt.
### wchar_t
- Mô tả: kí tự rộng
- Số byte: 2 hoặc 4 byte tùy máy
- Phạm vi giá trị: 0 đến 65,535 hoặc 0 → 2^32−1 tùy máy
- Ghi chú: cho Unicode
### wcin
- Kiểu: std::wistream
- Mô tả: Nhập dữ liệu wide
### wcout
- Kiểu: std::wostream
- Mô tả: Xuất dữ liệu wide
## Bool & Bit
### bool
- Kích thước: 1 byte
- Chỉ có 2 giá trị là true (1), false(0)
### byte (C++17)
- Kích thước: 1 byte
- Kiểu dữ liệu chỉ chứa dữ liệu dạng byte thuần túy, không có overload operator+, operator-
### vector<bool>
- Đơn giản là vector chứa các giá trị true/false, nhưng do nhiều yếu tố, phương pháp này chậm trong 1 số thao tác
### bitset<SIZE>
- Lưu trữ một tập hợp cố định các bit (kích thước biết trước tại compile-time).
- Thư viện: ```<bitset>```
## Literals
### General syntax: "YourString<Literal here>"
### Long Literal (1L)
- Kiểu dữ liệu: ```long``` hoặc ```long int```
### Unsigned Long Literal (1U)
- Kiểu dữ liệu: ```unsigned long```
### Long Long Literal (1LL)
- Kiểu dữ liệu: ```long long```
### Unsigned Long Long Literal (1ULL)
- Kiểu dữ liệu: ```unsigned long long```
### Signed Size Literal (1Z) (C++23)
- Kiểu dữ liệu: std::size_t hoặc std::ptrdiff_t
### Octal Literal (0123)
- Hệ bát phân (bắt đầu = 0)
### Hex Literal (0x123)
- Hệ thập lục phân (bắt đầu = 0x)
### Binary Literal (0b101)
- Hệ nhị phân (bắt đầu = 0b)
### Float Literal (.1f)
- Kiểu dữ liệu: ```float```
### Double Literal (.1)
- Kiểu dữ liệu: ```double```
### Long Double Literal (.1L)
- Kiểu dữ liệu: ```long double```
### Char Literal ('\n')
- Escape sequence: xuống dòng
### String Literal ("abc")
- Kiểu dữ liệu: ```const char[length]```
- Kết thúc bằng: ```\0```
### Raw String Literal (R"(raw\nstring)")
- Giữ nguyên tất cả, bỏ qua escape sequence
### Boolean Literal (true/false)
- Kiểu dữ liệu: ```bool```
### Digit Separator (123'456'789)
- Giúp số dễ đọc hơn mà không ảnh hưởng tới giá trị
## Cast
### C Cast (Type)(Data)
- Có trong C và được truyền qua C++
- Không an toàn, khó kiểm soát
```cpp
long long a = 9e5;
int b = (int)(a)//b = 9e5
```
### Static Cast static_cast<Type>(Data)
- Ép kiểu an toàn
- Được kiểm tra taị compile time
- Chỉ dùng được cho 1 số trường hợp nhất định
```cpp
long long a = 9e5;
int b = static_cast<int>(a)//b = 9e5
```
### Const Cast static_cast<Type>(Data)
- Bỏ hoặc thêm thuộc tính ```const``` hoặc ```volatile```
- Dễ lỗi/UB nếu dùng sai
```cpp
void print(const int* p) {
int* mod = const_cast<int*>(p);
*mod = 99;
}
```
### Reinterpret Cast: reinterpret_cast<Type>(Data)
- Dùng để ép kiểu thô – tức là chỉ thay đổi cách diễn giải vùng nhớ, không đổi dữ liệu.
- Dễ lỗi/UB nếu dùng sai
```cpp
long long a = 9e5;
void* b = reinterpret_cast<void*>(&a)//b = adress of a
```
### Dynamic Cast: dynamic_cast<Type>(Data)
- Ép kiểu OOP có kế thừ đa hình
- Có kiểm tra runtime
```cpp
class Base { public: virtual ~Base() {} };
class Derived : public Base {};
Base* b = new Derived;
Derived* d = dynamic_cast<Derived*>(b);
```
### Bit Cast: std::bit_cast
- Sao chép toàn bộ bit của đối tượng gốc sang kiểu mới mà không ép kiểu logic
- sizeof(Type1) == sizeof(Type2)
```cpp
float f = 1.0f;
uint32_t bits = std::bit_cast<uint32_t>(f);
```
## Scoping
### Global Scope ::x
- Truy cập biến toàn cục x (không phải x local)
```cpp
#include <bits/stdc++.h>
using namespace std;
string x = "signed p.diddy";
int main()
{
string x = "Hello world";
cout << ::x << " " << x;
return 0;
}
```
Output: signed p.diddy Hello world
### Variable Shadowing
- Khi biến cục bộ trùng tên với biến bên ngoài, biến bên trong shadow biến ngoài.
- Dễ gây nhầm lẫn và khó debug
```cpp!
#include <bits/stdc++.h>
using namespace std;
string x = "signed p.diddy";
int main()
{
string x = "Hello world";
cout << x;
return 0;
}
```
Output: Hello world
### Namespace namespace
- Gom nhóm các biến, hàm, lớp để tránh trùng tên
- Ví dụ: ```std```
### Nameless Namespace namespace
- Namespace không có tên, tạo liên kết nội bộ.
- Dùng để ẩn các biến/hàm khỏi các file khác.
```cpp!
#include <iostream>
namespace { // namespace vô danh
int b = 42;
void a() {
std::cout << "Hello!\n";
}
}
int main() {
a(); // OK
std::cout << b << '\n'; // OK
return 0;
}
Output: Hello!
42
```
### Static Storage Duration static (deprecated register)
- Biến static được khởi tạo 1 lần duy nhất và tồn tại suốt chương trình
- Scope: cục bộ
```cpp
static int a = 0;
```
### Static Constant Expressive constexpr constinit (C++20)
- constexpr: Biến hoặc hàm có thể tính toán tại compile-time (hằng biểu thức), biến sẽ mặc định là const
```cpp!
#include <bits/stdc++.h>
using namespace std;
constexpr int a = 5*5; //Giá trị tính toán được (5 x 5 = 25) và là hằng số
int main()
{
cout << a;
return 0;
}
```
Output: 25
- constinit (C++20): Đảm bảo biến tĩnh (static hoặc global) được khởi tạo tại compile-time (không phải constexpr), biến ko phải const, thay đổi được giá trị
```cpp!
#include <bits/stdc++.h>
using namespace std;
constinit int x = 10;
int main()
{
cout << x << "\n";
x = 100;
cout << x << "\n";
return 0;
}
```
### Thread Storage Duration thread_local
- khai báo biến có phạm vi lưu trữ theo từng luồng thực thi (thread)
- Mỗi thread sẽ có bản sao riêng của biến thread_local
- Không chia sẻ dữ liệu giữa các thread
- Không dùng trong LTTĐ(Codeforces), vì không dùng đa luồng (Mỗi task có lõi cpu giới hạn từ phía Cf, đa luồng làm context switch, dễ TLE hơn)
### Dynamic Storage Duration (new, new[], delete, delete[])
- Quản lí dữ liệu qua heap thủ công
- Dễ memory leak nếu không delete
```cpp
int a = new int(100);
delete a;
```
### Automatic Storage Duration (no static, no thread_local, no new, no new[])
- Xảy ra khi không dùng static, thread_local, new, ...
- Khi thoát khỏi một scope {}, biến bị hủy, kết thúc lifetime của nó
```cpp
#include <bits/stdc++.h>
using namespace std;
int main()
{
int X = 134;
return 0;
//X bị hủy tại đây
}
```
### External Linkage (inline, extern)
- inline: giúp tránh multiple definition, đồng thời tối ưu (có thể không tùy) bằng cách nhét hàm đó vào nơi gọi, giảm chi phí gọi hàm
```cpp!
#include <bits/stdc++.h>
using namespace std;
inline void Diddy(){cout << "Hello diddydiddy";}
int main()
{
Diddy(); // = cout << "Hello diddydiddy"
return 0;
}
```
Output: Hello diddydiddy
- extern: Khai báo biến hay hàm ở nơi khác (file cpp khác, .dll, .so,...)
- Chỉ tham chiếu, không tạo mới
```cpp!
extern int a;
extern "C" void Diddy() {
printf("Hello!\n");
}
```
### Internal Linkage
- Tên biến hay hàm chỉ được dùng trong 1 file c++, khai báo bên ngoài sẽ báo lỗi
### No Linkage
- Tên không thể chia sẻ giữa các file, chỉ tồn tại trong chính phạm vi của nó
- Ex: biến local, thành viên class, ...
### Block Scope {...}
- Tên tồn tại bên trong block, bị hủy khi ra khỏi block
- Cái này là compound statement và có trong if else switch
### Class Struct Scope (Access Specifier: public:, private:, protected:)
- Thành viên trong scope của class
- Chịu ảnh hưởng của Access Specifier public:, private:, protected:
- Liên quan đến OOP
- public: truy cập đc mọi nơi
- private: class hiện tại
- protected: class hiện tại + class con
### Lifetime
- Vòng đời của đối tượng
- Bắt đầu khi khai báo đối tượng và kết thúc khi ra khỏi scope {}
## Initialization
### Default Initialization int x;
- Khởi tạo biến x bình thường (x hiện tại là 0 nếu toàn cục, giá trị rác nếu trong hàm)
- Dễ UB
```cpp
#include <iostream>
using namespace std;
int main()
{
int x;
cout << x;
return 0;
}
```
```
Output: các giá trị rác
```
### Value Initialization int x{[value], if empty [value] = 0};
- Khởi tạo giá trị [value]
- An toàn
```cpp
#include <iostream>
using namespace std;
int main()
{
int x{};
int y{22};
cout << x << endl << y;
return 0;
}
```
```
Output: 0
22
```
### Zero Initialization static int x;
- Khởi tạo biến tĩnh x với giá trị đầu là 0 một lần duy nhất
- Cho biến global và local
- Giúp tránh gía trị rác
```cpp
#include <iostream>
using namespace std;
int main()
{
static int x;
cout << x;
return 0;
}
```
```
Output: 0
```
### Copy Initialization int x = 0;
- Giá trị của x bằng giá trị của expression sau dấu =, bằng phép sao chép
- Kiểu truyền thống, thường gặp
### Direct Initialization int x(0);
- Đơn giản là gán 0 vào x
- Dễ nhầm lẫn với khai báo hàm (hoặc lambda function)
```cpp!
#include <iostream>
using namespace std;
int main()
{
int x(0);
cout << x;
return 0;
}
```
```
Output: 0
```
### Scalar List Initialization int x = {0}; (Narrowing Safe)
- Khởi tạo x với 0
- Narrowing safe, giúp tránh mất dữ liệu khi explicit cast khác kiểu
```cpp
#include <iostream>
using namespace std;
int main()
{
int x = {0};
cout << x;
return 0;
}
```
```
Output: 0
```
### Copy List Initialization vector<int> x = vector<int>{0, 0};
- Khởi tạo giá trị cho vector với kiêủ dữ liệu int bằng phép sao chép
```cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> x = vector<int>{0, 0};
for(int a : x) cout << a << endl;
return 0;
}
```
```
Output: 0
0
```
### Direct List Initialization vector<int> x{0, 0};
- Khởi tạo vector với giá trị trực tiếp (init value)
```cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> x{0, 0};
for(int a : x) cout << a << endl;
return 0;
}
```
```
Output: 0
0
```
### Initializer List Initialization std::initializer_list<T> var = {..};
- Khởi tạo các phần tử của container bằng initializer_list được bọc trong {}
- Có thư viện dùng initializer_list để khởi tạo: <initializer_list>
### Reference Initialization int &x = dp[const_cat][const_card][const_cart];
- Khởi tạo biến x tham chiếu tới 1 mảng 3 chiều tới index const_cat, const_card, const_cart
- Giá trị trong index của mảng bị tham chiếu bị thay đổi khi mảng tham chiếu thay đổi
### Constant Initialization const int x = 0;
- Khởi tạo biến x với giá trị hằng số (không thể gán lại)
- Keyword: const
### Array Initialization int x[2]{};
- Khởi tạo mảng với số phần tử là 2, cho giá trị mỗi phần tử là 0
- Giống Zero-Fill Array Initialization nhưng ko cần delete
### Dynamic Initialization int *x = new int(0); (new)
- Kiểu khởi tạo động trên heap (x sẽ trả về địa chỉ của giá trị trên heap, lấy giá trị thì ghi *x)
- Memory leak nếu không delete
```cpp!
#include <iostream>
using namespace std;
int main()
{
int *a = new int(67);
cout << *a;
delete a;//Tuy vậy, ta ko cần delete ở đây vì a sẽ bị hủy khi chương trình kết thúc
return 0;
}
```
Output: 67
### Zero-Fill Array Initialization int *x = new int[2] (); (new[])
- Khởi tạo giống cấp phát động như trên, với một kích thước cho sẵn, cho giá trị mỗi phần tử là 0
- Cẩn thận giá trị rác
```cpp
#include <bits/stdc++.h>
using namespace std;
int main()
{
int *x = new int[2] ();
cout << x[0];
return 0;
}
```
Output: 0
### Dynamic Array Initialization int *x = new int[2]{0,0}; (new[])
- Cấp phát mảng động 2 phần tử, khởi tạo giá trị mỗi phần tử bằng 0
- Cần delete[] sau khi dùng (nếu không là memory leak)
### Member Initialization struct Int { int member; Int(int param) : member(param) {} }
```cpp
struct Int {
int member;
Int(int param) : member(param) {}
};
```
- Khởi tạo trực tiếp thành viên thông qua constructor initailizer list
### Default Member Initialization struct Int{ int member = 0; } (NSDMI)
- NSDMI – Non-static Data Member Initialization
- Khởi tạo giá trị của đối tượng trong struct ngay trong struct
### String Literal Initialization const char name[] = "SPy"; (utf8, unicode, wchar, signed char, unsigned chah, char)
- Khởi tạo mảng hằng kí tự từ một string literal
- Có các kiểu utf 8, unicode, wide char, signed char, unsigned char, char
### Structured Binding Initialization for (auto [u, v] : edges) {}
- Cho phép tách các giá trị của pair hoặc tuple thành 2 biến
- Rất tiện vì không phải dùng first, second để truy cập giá trị
### Control Flow Initialization if (int x = 0; x > 0) {}
- Khởi tạo biến ngay trong scope của if, for, switch
- BIến chỉ tồn tại trong scope (ra ngoài sẽ bị hủy)
### Partial Aggregate Initialization int x[5]{1, 2};
- Chỉ xác định giá trị của một phần mảng
- Phần còn lại đều có giá trị 0
### Direct Aggregate Initialization Pair p(1, 2);
- Khởi tạo trực tiếp thành viên của một aggregate type bằng constructor
### Designated Initialization Pair x = { .first = 1, .second = 2 }; (C++20)
- Khởi tạo các đối tượng của pair (container chứa 2 phần tử là .first và .second)
- .first: phần tử đầu tiên
- .second: phần tử thứ hai
- std::pair không hỗ trợ, nên dùng struct
```cpp
#include <bits/stdc++.h>
using namespace std;
int main()
{
pair<int, int> a = {.first = 36, .second = 67};
return 0;
}
```
Error:
main.cpp: In function ‘int main()’:
main.cpp:6:50: error: designated initializers cannot be used with a non-aggregate type ‘std::pair’
6 | pair<int, int> a = {.first = 36, .second = 67};
| ^
```cpp!
#include <bits/stdc++.h>
using namespace std;
int main()
{
struct pair{
int first;
int second;
};
pair a = {.first = 36, .second = 67};
cout << a.first << " " << a.second;
return 0;
}
```
Output: 36 67
### Designated Aggregate Initialization T object = { .var1 = arg1, .var2 { arg2 } }
- Có thể dùng cho struct, v.v, miễn đáp ứng
- Giá trị mặc định là 0
- Ví dụ (như ở trên)
```cpp!
#include <bits/stdc++.h>
using namespace std;
int main()
{
struct pair{
int first;
int second;
};
pair a = {.first = 36, .second = 67};
cout << a.first << " " << a.second;
return 0;
}
```
Output: 36 67
### Lambda Capture Initialization auto test = [&bind=target](){};
- Khởi tạo một biến trực tiếp trong capture list của lambda
- Ví dụ:
```cpp
int a = 5;
auto lambda = [x = a + 10]() {
return x * 2;
};
std::cout << lambda(); // 30
```
### Pointer Null Initialization int *ptr{};
- Khởi tạo với giá trị nullptr
```cpp!
#include <iostream>
using namespace std;
int main()
{
int *ptr{};
cout << (ptr == nullptr);
return 0;
}
```
```
Output: 1 (true)
```
## Unary Operators
### +X Unary Plus
- Không thay đổi giá trị, chỉ biểu thị rằng X là số dương
- Ít dùng (phế vật)
```cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int a = -9;
a = +a;
cout << a;
return 0;
}
```
```
Output: -9
```
### -X Unary Minus
- Biểu thị X là số âm
```cpp!
#include <iostream>
using namespace std;
int main()
{
int a = 9;
a = -a;
cout << a;
return 0;
}
```
```
Output: -9
```
### !X Negation
- Đảo flag true thành false, false thành true
```cpp!
#include <iostream>
using namespace std;
int main()
{
bool a = true;
bool b = false;
cout << !a << endl << !b;
return 0;
}
```
```
Output: 0
1
Lưu ý: 0 -> false
1 -> true
```
### ~X Bitwise NOT
- Đảo tất cả các bit của x (vd: 1100 thành 0011) (bit 1 -> bit 0 và ngược lại)
### ++X Pre Increment
- Tăng X lên 1 rồi trả về giá trị mới
```cpp
#include <iostream>
using namespace std;
int main()
{
int a = 10;
cout << ++a << endl << a;
return 0;
}
```
```
Output: 11
11
```
### --X Pre Decrement
- Giảm X xuống 1 rồi trả về giá trị mới
```cpp
#include <iostream>
using namespace std;
int main()
{
int a = 10;
cout << --a << endl << a;
return 0;
}
```
```
Output: 9
9
```
### X++ Post Increment
- Trả về giá trị hiện tại rồi tăng X lên 1
```cpp
#include <iostream>
using namespace std;
int main()
{
int a = 10;
cout << ++a << endl << a;
return 0;
}
```
```
Output: 10
11
```
### X-- Post Decrement
- Trả về giá trị hiện tại rồi giảm X xuống 1
```cpp
#include <iostream>
using namespace std;
int main()
{
int a = 10;
cout << a-- << endl << a;
return 0;
}
```
```
Output: 10
9
```
## Arithmetic Operators
### A+B Addition Plus
- Trả về tổng A và B
### A-B Subtraction Minus
- Trả về hiệu A và B
### A*B Multiplication Multiply
- Trả về tích A và B
### A/B Division Div
- Trả về thương A và B
### A%B Remainder Mod
- Trả về số dư của A/B
### A+=B Assignment Addition
- Cộng thêm B vào số A
- A = A + B
### A-=B Assignment Subtraction
- Trừ đi B vào số A
- A = A - B
### A*=B Assignment Multiplication
- Nhân B vào số A
- A = A * B
### A/=B Assignment Division
- Chia B vào số A
- A = A/B
### A%=B Assignment Remainder
- Mod B vào số A
- A = A%B
## Comparison Operators
### A<B Less LE
- True nếu số A bé hơn số B
### A<=B Less Or Equal LEQ
- True nếu số A bé hơn hoặc bằng số B
### A>B Greater GE
- True nếu số A lớn hơn số B
### A>=B Greater Or Equal GEQ
- True nếu số A lớn hơn hoặc bằng số B
### A==B Equal EQ
- True nếu số A bằng số B
### A!=B Not Equal NEQ
- True nếu số A không bằng số B
### A<=>B Three-way Spaceship Operator
- Toán tử so sánh ba chiều
- Trả về đối tượng so sánh
```cpp
std::partial_ordering::less
std::partial_ordering::equivalent
std::partial_ordering::greater
std::partial_ordering::unordered
```
## Logic Operators
### A&&B Logic And
- Trả true (1) nêú cả 2 đúng
### A||B Logic Or
- Trả true (1) nếu 1 trong 2 đúng
### There is no Logic Xor Operator
- C++ không có toán tử logic XOR cho bool
### Short Circuit
- Giúp an toàn, tránh RTE
- Các ví dụ:
```cpp
a || b //a true => dừng và trả về true
a && b //a false => dừng và trả về false
```
## Bitwise Operators
### A<<B Shift Left
- Dịch trái bit của A sang B vị trí, thêm 0 bên phải
### A>>B Shift Right
- Dịch phải bit của A sang B vị trí
### A^B XOR
- Bit bật nếu bit của A khác bit của B
### A&B AND
- Bit bật khi cả bit của A và B đều bật
### A|B OR
- Bit bật khi 1 trong 2 bit của A hay B bật
### A<<=B Assignment Shift Left
- Dịch trái bit của A B vị trí rồi gán cho A
- A = A << B
### A>>=B Assignment Shift Right
- Dịch phải bit của A B vị trí rồi gán cho A
- A = A >> B
### A^=B `Assignment XOR
- A xor B rồi gán cho A
- A = A ^ B
### A&=B Assignment AND
- A and B rồi gán cho A
- A = A & B
### A|=B Assignment OR
- A or B rồi gán cho A
- A = A | B
### ~A UNARY NOT
- Trả về giá trị các bit đã bị đảo của A
## Operator Overloadding
### Unoverloadable Operators ::, ., .*, ?:
### Custom Assignment Operator =
### Custom Function Call Operator ()
### Custom Subscript Operator []
### Custom Multidimensional Subscript Operator (comma operator, C++23 [])
### Custom Logic And Operator &&
### Custom Logic And Operator ||
### Custom Comma Operator ,
### Custom Member Access Operator ->
### Custom Pointer Member Access Operator ->*
### Custom New Operator new new[]
### Custom Delete Operator delete delete[]
### User-defined Literals Operator ""_s()
### Explicit Conversion Operator explicit operator T()
### Boolean Explicit (Supressing Implicit Conversion) Operator explicit operator bool()
### Comparison Suite: strong ordering, partial ordering, poset
## Order
### Operator Prescedence
### Evaluation Order
### Sequence Cases
### Assignment Sequence Points
### Function Call Arguments Order
### Order of Evaluation
```cpp!
auto ReadInt() -> int {
int x;
cin >> x;
return x;
}
int x = ReadInt();
int l = ReadInt(), r = ReadInt();
pair<int, int> q = pair<int, int>(l, r);
pair<int, int> p = pair<int, int>(ReadInt(), ReadInt());
cout << x << "\n" << p.first << " " << p.second << "\n";
txt.input
1
2 3
2 3
txt.output
1
3 2
```
### Lexicographical Order
## Enum
### Enum
- Kiểu dữ liệu truyền thống C++
- Giá trị trong enum là int, được chuyển ra ngoài scope enum
- Mặc định giá trị theo thứ tự bắt đầu từ 0 (trừ khi gán thủ công)
- Mặc định:
```cpp
enum Numbers{
Zero, //0
One, //1
Two //2
}
cout << Zero;
```
- Gán giá trị:
```cpp!
enum Numbers{
Zero = 13, //13
One = 99, //99
Two = 2 //2
}
cout << Zero;
```
### Enum Class
- Kiểu dữ liệu mới trong C++
- Giống enum nhưng phải dùng <Tên Enum>::<Tên BIến> vì ko được chuyển ra scope ngoài, tránh lỗi trùng lặp
```cpp
enum class Numbers{
Zero, //0
One, //1
Two //2
}
cout << Numbers::Zero;
```
### Enum Size
- Áp dụng cho ```enum```, ```enum class```
#### Enum mặc định
- Kích thước thường được chỉ định là ```sizeof(int)``` trên hầu hết compiler
#### Enum được chỉ định kiểu
- Cú pháp:
```cpp
enum Color : unsigned char { RED, GREEN, BLUE };
```
- Kích thước là kích thước của kiểu được chỉ định
## Template
### Generic
- Lập trình hàm tái sử dụng được với các kiểu mà ko gây CPE
- Có thể dùng: template<typename T>, decltype, auto, ...
- Ví dụ ứng dụng:
```cpp
vector<T>
map<K, V>
```
### TMP
- Full name: Template Meta Programming
- Dùng template để code bằng kiểu và tính toán ra giá trị tại compile-time
```cpp!
#include <iostream>
using namespace std;
template<typename T, typename B>
auto sum(T a, B b){
return a+b;
}
int main()
{
cout<<sum(5,6.1) << endl;
cout<<sum(-5LL, 22ULL);
return 0;
}//C++ 14 trở đi, đúng khi A và B đều là số
```
Output: 11.1
17
### SFINAE
- Full name: Substitution Failure Is Not An Error (gg dịch: Thất bại thay thế không phải là lỗi)
- Khi thay thế kiểu thất bại, compiler không báo lỗi mà bỏ qua hàm đó luôn
- Giúp an toàn hơn (tránh CPE)
## Preprocessor
### #define
- Macro tiền xử lí, thay thế bằng văn bản, không kiểm tra kiểu
```cpp
#define int long long //Trick
```
### #pragma
- Tùy chọn, chỉ thị cho compiler
- Hay dùng:
```cpp!
#pragma once
#pragma GCC optimize("optimize here") //Cho GCC
#pragma optimize("optimize here") //Cho các trình biên dịch khác
```
Tối ưu hóa (Ko dùng trong codeforces)
### File Guard #ifndef #ifdef #elif #endif
- Tránh lỗi định nghĩa trùng lặp khi include nhiều lần một header file .h
```cpp!
#ifndef MY_HEADER_H
#define MY_HEADER_H
// nội dung file .h
#endif
```
### Build Flags (-O2, -pipe, -static, -Wall, -Wextra)
- Tùy chọn build khi build qua dòng lệnh g++
```
g++ Main.cpp -o main <Build flags>
```
(Cho thí sinh nào dùng notepad đi thi HSG)
## IO
### ios::sync_with_stdio(false);
- Tắt đồng bộ hóa luồng nhập xuất C++ (cin, cout) với luồng nhập xuất C truyền thống (printf, scanf)
### cin.tie(nullptr);
- cin được buộc với cout, nên khi người dùng nhập vào sẽ flush cout, gây giảm hiệu năng
- Buộc cin với nullptr giúp tăng hiêụ năng, rất hữu ích trong LTTĐ
### cout.tie(nullptr);
- Buộc cout với nullptr
- Không cần vì cout không bị buộc với cin
### FastIO (getchar, putchar)
- Thư viện: <cstdio>
- Không đồng bộ hóa, không flush,... nên nhanh hơn
- Dùng tốt trong competitive programming
### Unsafe FastIO (getchar_unlocked, putchar_unlocked)
- Giống như getchar, putchar nhưng ko khóa buffer (nhanh hơn nữa), nguy hiểm đa luồng
- Trong LTTĐ ko được đa luồng nên vẫn an toàn
## Math
### abs()
- Giá trị tuyệt đối
- #include <cmath>
### gcd()
- Ước chung lớn nhất
- #include <numeric>
### lcm()
- Bội chung nhỏ nhất
- #include <numeric>
### min()
- Số nhỏ nhất
- #include <algorithm>
### max()
- Số lớn nhất
- #include <algorithm>
### sqrt()
- Căn bậc 2
- #include <cmath>
### pow()
- Lũy thừa
- #include <cmath>
- #include <numeric> cho C++17+
## Debug
### Runtime Assert
Trong ```<cassert>```, hàm ```assert()``` là 1 ví dụ về runtime assert (kiểm tra giá trị tại runtime và ép terminate (abort) chương trình khi giá trị không bằng, đồng thời in ra lỗi)
### Static Assert
- Kiểm tra điều kiện tại thời điểm biên dịch
- Thư viện: ```<type_traits>```
- Cú pháp: ```static_assert(condition, errorMsgIfAssertionFailed)```
## Include
### <bits/stdc++.h>
Thư viện tổng hợp trong C++
### Free Standing Library
- Freestanding Library là tập hợp con tối thiểu của C++ Standard Library được tồn tại trong freestanding (môi trường không phụ thuộc, không STL)
## STL
### std::array
- Container mảng tĩnh, kích thước được xác định tại thời điểm biên dịch
- Hiệu năng tương đương mảng trong C nhưng an toàn hơn
- Thư viện: ```<array>```
### std::vector
- Container mảng động, kích thước được điều chỉnh tự động
- Hiệu năng chậm hơn array một chút
- Thư viện: ```<vector>```
## Alias
### Using
```cpp
using ll = long long;
template<typename T>
using Vec = std::vector<T>;
Vec<int> a; // std::vector<int> a;
Vec<char> b; // std::vector<char> b;
using namespace std;
using std::cout;
```
- ```using``` là cách hiện đại để đặt tên một alias trong C++, có alias cho template
- Cú pháp: ```using alias = type;``` (Tất cả những kiểu tên alias sẽ được thay thế bằng kiểu type)
### typedef
```cpp
typedef long long ll;
```
- Cũng dùng để dặt alias như using
- Cực dễ gây lú nếu lồng ghép, không hỗ trơ template
### lvalue&
```cpp
const int LIM = 2e5 + 25;
long long dp[LIM];
auto f(int i, int j, int k,
int upperR, int lowerR, bool ilzr, bool itzr,
int upperL, int lowerL, bool ilzl, bool itzl
) -> long long
{
if (i <= 0) {
return 1;
}
auto &res = dp[i][j][k][upperR][lowerR][ilzr][itzr][upperL][lowerL][ilzl][itzl];
if (res != -1) {
return res;
}
res = f(i - 1) * i;
return res;
}
memset(dp, -1, sizeof(dp));
```
- Dấu & dùng để tham chiếu tới một biến hoặc một mảng
- Khi giá trị của biến tham chiếu thay đổi, biến bị tham chiếu cũng sẽ bị thay đổi (có thể nói biến tham chiếu là alias của biến bị tham chiếu)
## Constants & Enums
### Constants
- Các giá trị hằng số, giá trị không thể bị thay đổi, nêú thay đổi lập tức CPE
- Ví dụ
```cpp
const int a = 3;
constexpr int a = 2+2;
#define int "Hello"
enum { RED = 1, GREEN = 2, BLUE = 3 };
enum class Color { RED, GREEN, BLUE };
```
## Time
### <chrono>
- Thư viện liên quan đến thời gian (tính toán thời gian thực thi, lấy giá trọ thời gian hiện tại hay tính khoảng thời gian)
- Cú pháp: ```#include <chrono>```
### system_clock
- Cú pháp: ```std::chrono::system_clock```
- Dùng để lấy thời gian trong hệ thống (nó giống như mục thời gian ở bên phải trong windows taskbar)
- Có thể dùng để lấy thời gian của hệ thống, tính toán thời gian, chuyển đổi thời gian, etc
- Ví dụ:
```cpp
#include <iostream>
#include <chrono>
#include <ctime>
int main() {
auto now = std::chrono::system_clock::now();
std::time_t now_time = std::chrono::system_clock::to_time_t(now);
std::cout << std::ctime(&now_time);
return 0;
}
```
### steady clock
- Đo khoảng thời gian trôi qua kể từ một mốc thời gian nào đó (từ khi declare biến steady_clock)
- Dùng để đo thời gian thực thi, thời gian đã trôi qua
- Ví dụ:
```cpp
#include <iostream>
#include <chrono>
#include <thread>
int main() {
auto start = std::chrono::steady_clock::now();
auto end = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << elapsed.count() << " ms\n";
}
```
### high_resolution_clock
- Cung cấp số tick nhỏ nhất
- Có thể là alias của system_clock hoặc steady_clock tùy compiler