# OAI # ## I. Implementation Fundamentals ## ### I.1: Statements ### #### I.1-a: Single Statement #### ```cpp! #include <iostream> using namespace std; int main(){ int n=3; return 0; } ``` #### I.1-b: Compound Statement #### ```cpp! #include <iostream> using namespace std; int main(){ for(int i=0; i<3; i++){ cout<<i<<" "; } return 0; } ``` #### I.1-c #### **If else** ```cpp! #include <iostream> using namespace std; int main(){ int n; cin>>n; if(n%2==0) cout<<"het"; else cout<<"du"; return 0; } ``` #### I.1-d: switch case #### ```cpp! #include <iostream> using namespace std; int main(){ int n; cin>>n; switch(n){ case 1: cout<<"Monday"; break; case 5: cout<<"Tuesday"; break; case 3: cout<<"Wednesday"; break; case 2: cout<<"Thursday"; break; case 0: cout<<"Friday"; break; case 7: cout<<"Saturday"; break; case 9: cout<<"Sunday"; break; default: cout<<"haha"; } return 0; } ``` #### I.1-e: ternary operator #### ```cpp! #include <iostream> using namespace std; int main(){ int n; cin>>n; cout<<(n%2==0)?0:1; return 0; } ``` #### I.1-f: while #### ```cpp! #include <iostream> using namespace std; int main(){ int n; cin>>n; while(n--) cout<<n<<" "; return 0; } ``` #### I.1-g: do while #### ```cpp! #include <iostream> using namespace std; int main(){ int n; cin>>n; do cout<<n--<<" "; while(n==0); return 0; } ``` #### I.1-h: for #### ```cpp! #include <iostream> using namespace std; int main(){ int n; cin>>n; for(int i=0; i<n; i++) cout<<i<<" "; return 0; } ``` #### I.1-i: range-for #### ```cpp! #include <iostream> #include <vector> using namespace std; int main(){ int n; cin>>n; vector <int> v(n); for(int i:v) cout<<i<<" "; return 0; } ``` #### I.1-j: continue #### ```cpp! #include <iostream> using namespace std; int main(){ int n; cin>>n; for(int i=0; i<n; i++){ if(i%2==0) continue; } return 0; } ``` #### I.1-k: break #### ```cpp! #include <iostream> using namespace std; int main(){ int n,x; cin>>n>>x; for(int i=0; i<n; i++) { if(i==x) break; cout<<i<<" "; } return 0; } ``` #### I.1-l: goto #### ```cpp! #include <iostream> using namespace std; int main(){ int n,x; cin>>n>>x; if(n==x) goto haha; cout<<"NO"; return 0; haha: cout<<"YES"; return 0; } ``` #### I.1-m: return #### ```cpp! #include <iostream> using namespace std; int main(){ int n,x; cin>>n>>x; return 0; } ``` #### I.1-n: while(true)/for(;;) #### ```cpp! #include <iostream> using namespace std; int main(){ int n; cin>>n; while(true){ cout<n++; } return 0; } ``` #### I.1-o: for (auto [u, v] : edges) (C++17) #### dùng để duyệt qua các cặp giá trị ```cpp! #include <iostream> #include <vector> using namespace std; int main(){ vector<pair<int,int>> edges={{1,2},{2,3},{3,4}}; for(auto [u,v]:edges) cout<<u<<" "<<v<<'\n'; return 0; } ``` ### I.2: Int Types ### #### I.2-a: int #### KDL: số nguyên kích thước: >=2byte Khoảng: -2,147,483,648 đến 2,147,483,647 dùng để lưu số nguyên, không có phần thập phân (âm và dương). #### I.2-b: unsigned int #### KDL: số nguyên(không âm) kích thước: >=4byte Khoảng: 0 đến 4.294.967.295 dùng để lưu số tự nhiên, không lưu được số âm #### I.2-c: long long #### KDL: số nguyên kích thước: 8byte Khoảng: -9,223,372,036,854,775,808 đến 9,223,372,036,854,775,807 dùng để lưu số nguyên, không có phần thập phân, lưu được số lớn hơn kiểu int(âm và dương). #### I.2-d: unsigned long long #### KDL: số nguyên(không âm) kích thước: 8byte Khoảng: 0 đến 18,446,744,073,709,551,615 dùng để lưu số tự nhiên(không âm), không có phần thập phân, lưu được số lớn hơn kiểu int, unsigned int. #### I.2-e: short #### KDL: số nguyên kích thước: 2byte Khoảng: −32,768 đến 32,767 dùng để lưu số nguyên,lưu được số nhỏ hơn int(âm và dương). #### I.2-f: unsigned short #### KDL: số nguyên(không âm) kích thước: 2byte Khoảng: 0 đến 65,535 dùng để lưu số tự nhiên,lưu được sốtự nhiên nhỏ hơn int. #### I.2-g: int8_t #### KDL: số nguyên kích thước: 8bit(1byte) khoảng: -128 đến 127 dùng để lưu số nguyên(âm và dương). #### I.2-h: int16_t #### KDL: số nguyên kích thước: 16bit(2byte) khoảng: -32,768 đến 32,767 dùng để lưu số nguyên(âm và dương). #### I.2-i: int32_t #### KDL: số nguyên kích thước: 32bit(4byte) khoảng: -2,147,483,648 đến 2,147,483,647. dùng để lưu số nguyên(âm và dương). #### I.2-j: int64_t #### KDL: số nguyên kích thước: 64bit(8byte) khoảng: -9,223,372,036,854,775,808 đến 9,223,372,036,854,775,807 dùng để lưu số nguyên(âm và dương). #### I.2-k: uint8_t #### KDL: số nguyên(không âm) kích thước: 8bit(1byte) khoảng: 0 đến 255 dùng để lưu số nguyên dương. #### I.2-l: uint16_t #### KDL: số nguyên(không âm) kích thước: 16bit(2byte) khoảng: 0 đến 65535 dùng để lưu số nguyên dương. #### I.2-m: uint32_t #### KDL: số nguyên(không âm) kích thước: 32bit(4byte) khoảng: 0 đến 4,294,967,295 dùng để lưu số nguyên dương. #### I.2-n: uint64_t #### KDL: số nguyên(không âm) kích thước: 64bit(8byte) khoảng: 0 đến 18,446,744,073,709,551,615 dùng để lưu số nguyên dương. #### I.2-o: size_t #### KDL: số nguyên(không âm) kích thước: 32bit/64bit khoảng: 0 đến 4,294,967,295 / 18,446,744,073,709,551,615 dùng để lưu số nguyên dương (thường được trả về bởi sizeof). #### I.2-p: ssize_t(C++20) #### KDL: số nguyên Kích thước: 32bit/64bit Khoảng: -2,147,483,648 đến 2,147,483,647 / -9,223,372,036,854,775,808 đến 9,223,372,036,854,775,807 dùng để lưu số nguyên (dương và âm), thường dùng trong các hàm hệ thống như read(), write() để trả về số byte. ### I.3: Float Types ### #### I.3-a: Float #### KDL: số thực Kích thước: 32bit(4byte) Khoảng: ±1.18 × 10⁻³⁸ đến ±3.4 × 10³⁸ Độ chính xác khoảng 6 chữ số thập phân. #### I.3-b: Double #### KDL: số thực Kích thước: 64bit(8byte) Khoảng: ±2.23 × 10⁻³⁰⁸ đến ±1.80 × 10³⁰⁸ Độ chính xác khoảng 15 chữ số thập phân. #### I.3-c: Long Double #### KDL: số thực Kích thước: 8/12/16 byte Khoảng: ±3.36 × 10⁻⁴⁹³² đến ±1.19 × 10⁴⁹³² Độ chính xác khoảng 18-21 chữ số thập phân. ### I.4: Char & String Types ### #### I.4-a: Char #### KDL: ký tự Kích thước: 8bit(1byte) Dùng để lưu 1 ký tự, vd: "A","6","%". #### I.4-b: Signed Char #### KDL: số nguyên Kích thước: 8bit(1byte) Khoảng: -128 đến 127 Dùng để lưu số nguyên (dương và âm) nhỏ. #### I.4-c: Unsigned Char #### KDL: số nguyên (không âm) Kích thước: 8bit(1byte) Khoảng: 0 đến 255 Dùng để lưu số nguyên dương nhỏ hoặc dữ liệu nhị phân. #### I.4-d: string #### KDL: chuỗi ký tự Kích thước: không cố định Dùng để lưu 1 chuỗi ký tự, vd: "abc","a","123896" #### I.4-e: string_view #### KDL: chuỗi ký tự Kích thước: 16byte không chứa dữ liệu chuỗi riêng, mà chỉ chỉ vào một phần của chuỗi ở nơi khác trong bộ nhớ, chỉ lưu con trỏ đến vị trí bắt đầu và độ dài của chuỗi mà nó “nhìn thấy”. #### I.4-f: fstream #### KDL: lớp Kích thước: không cố định dùng để mở, đọc, ghi, và đóng file, dùng để thao tác file. #### I.4-g: ifstream #### KDL: lớp Kích thước: không cố định dùng để mở, đọc, ghi, và đóng file, dùng để mở và đọc dữ liệu từ file. #### I.4-h: ofstream #### KDL: lớp Kích thước: không cố định dùng để mở, đọc, ghi, và đóng file, dùng để mở và ghi dữ liệu vào file. #### I.4-i: stringstream #### KDL: lớp Kích thước: không cố định dùng để đọc và ghi dữ liệu qua chuỗi ký tự như một luồng, hỗ trợ chuyển đổi kiểu dữ liệu dễ dàng. #### I.4-j: istringstream #### KDL: lớp Kích thước: không cố định dùng để trích xuất dữ liệu từ chuỗi ký tự dưới dạng luồng nhập. #### I.4-k: ostringstream #### KDL: lớp Kích thước: không cố định dùng để ghi dữ liệu vào chuỗi ký tự dưới dạng luồng xuất. #### I.4-l: char8_t (C++20) #### - dùng để biểu diễn ký tự mã hóa UTF-8 - Kích thước: 1 byte (8 bit) - Mã hóa: UTF-8 #### I.4-m: char16_t #### - dùng để biểu diễn ký tự mã hóa UTF-16 - Kích thước: 2 byte (16 bit) - Mã hóa: UTF-16 #### I.4-n: char32_t #### - dùng để biểu diễn ký tự mã hóa UTF-32 - Kích thước: 4 byte (32 bit) - Mã hóa: UTF-32 #### I.4-o: istream #### KDL: lớp dùng làm luồng nhập (input stream) để đọc dữ liệu. #### I.4-p: ostream #### KDL: lớp dùng làm luồng xuất (output stream) để ghi dữ liệu. #### I.4-q: cin #### - là một đối tượng được định nghĩa trước trong thư viện iostream, thuộc lớp istream - nhận dữ liệu đầu vào từ thiết bị nhập chuẩn #### I.4-r: cout #### - là một đối tượng được xác định trước của lớp ostream - kết nối với thiết bị đầu ra tiêu chuẩn #### I.4-s: cerr #### - là một thể hiện của lớp ostream - sử dụng khi thông báo lỗi cần được hiển thị ngay lập tức #### I.4-t: clog #### - là một đối tượng thuộc thư viện iostream - sử dụng để ghi thông báo hoặc thông tin vào luồng log chuẩn #### I.4-u: Escape Character ('\n', '\\', '\'', '\"', ...) #### - dùng để thể hiện ký tự điều khiển hoặc ký tự không in được trong chuỗi hoặc ký tự #### I.4-v: Escape Sequence ('\nnn', '\o{nnn}', '\xnnn', '\x{nnn}', ...) #### - dùng để biểu diễn giá trị nhị phân, bát phân, thập lục phân (hex) trực tiếp trong chuỗi hoặc ký tự - chèn ký tự không gõ được bằng bàn phím hoặc ký tự điều khiển #### I.4-w: wchar_t #### KDL: ký tự Kích thước: 2 - 4 byte(tùy hệ thống) Dùng để lưu nhiều ký tự, vd: "A","6","%", có thể lưu ký tự đặc biệt như tiếng Việt, Trung,.. #### I.4-x: wcin #### - giống cin nhưng dùng với wchar_t #### I.4-y: wcout #### - giống cout nhưng dùng với wchar_t ### I.5: Bool & Bit ### #### I.5-a: Bool #### KDL: logic Kích thước: 8bit(1byte) giá trị: true(1) và false(0) đại diện cho logic đúng/sai #### I.5-b: Byte(C++17) #### - dùng để làm việc với dữ liệu dạng thô trong bộ nhớ - 1byte(8bit) #### I.5-c: Vector[bool] #### - Nằm trong thư viện vector - Mỗi phần tử chiếm 1 bit, không phải 1 byte\ #### I.5-d: Bitset(size) #### ### I.6: Literals ### #### I.6-a: Long Literal (1L) #### - KDL: long int - Hậu tố: L/l, ví dụ: 1L/1l - ép literal sang kiểu long #### I.6-b: Unsigned Long Literal (1U) #### - KDL: unisgned int - Hậu tố: u/U, ví dụ: 1u/1U - ép literal sang kiểu số nguyên không dấu #### I.6-c: Long Long Literal (1LL) #### - KDL: long long - Hậu tố: LL/ll, ví dụ: 1LL/1ll - ép literal sang kiểu long long #### I.6-d: Unsigned Long Long Literal (1ULL) #### - KDL: unsigned long long int - Hậu tố: ULL/ull, ví dụ: 1ULL/1ull - ép literal sang kiểu unsigned và long long #### I.6-f: Signed Size Literal (1Z) (C++23) #### - std::size_t - Hậu tố: Z/z, ví dụ: 1Z/1z - ép literal sang kiểu size_t #### I.6-g: Octal Literal (0123) #### - octal - Hậu tố: 0123 - số hệ bát phân #### I.6-h: Hex Literal (0x123) #### - hex - Hậu tố: 0x123 - số hệ thập lục phân #### I.6-i: Binary Literal (0b101) #### - binary - Hậu tố: 0b101 - số hệ nhị phân #### I.6-j: Float Literal (.1f) #### - KDL: Float - Hậu tố: F/f, ví dụ: .1F/.1f - dùng để chỉ literal là float #### I.6-k: Double Literal (.1) #### - KDL: Double - Hậu tố: không có, ví dụ: .1/.1 - dùng để chỉ literal là double #### I.6-l: Long Double Literal (.1L) #### - KDL: long double - Hậu tố: L/l, ví dụ: .1L/.1l - dùng khi cần độ chính xác cao hơn double #### I.6-m: Char Literal ('\n') #### - KDL: Char ```cpp! char a='1'; char c='f'; ``` #### I.6-n: String Literal ("abc") #### - KDL: String ```cpp! string s="avnfs"; string so="01352"; ``` #### I.6-o: Raw String Literal (R"(raw\nstring)") #### #### I.6-p: Boolean Literal (true/false) #### - KDL: Bool ```cpp! bool ok= true; ``` #### I.6-z: Digit Separator (123'456'789) #### - dùng để phân tách số cho dễ đọc ```cpp! int a=111'111//=111111 ``` ### I.7: Cast ### #### I.7-a: C Cast (Type)(Data) #### I.7-b: Static Cast `static_cast<Type>(Data)` #### #### I.7-c: Const Cast `const_cast<Type>`(Data) #### #### I.7-d: Reinterpret Cast: `reinterpret_cast<Type>(Data)` #### #### I.7-e: Dynamic Cast: `dynamic_cast<Type>(Data)` #### #### I.7-f: Bit Cast: std::bit_cast #### ### I.8: Scoping ### #### I.8-a: Global Scope ::x #### - biến nằm ngoài hàm ```cpp! int x; int main(){ ::x=10; return 0; } ``` #### I.8-b: Variable Shadowing #### - nếu có biến x nằm trong và nằm ngoài hàm thì, thì lệnh trong hàm đó sẽ sử dụng biến x nằm trong hàm, muốn dùng biến x ngoài hàm thì viết ::x ```cpp! int x=10; int main(){ int x=5; cout<<x;//in ra 5 cout<<"\n"<<::x;//in ra 10 } ``` #### I.8-c: Namespace namespace #### #### I.8-d: Nameless Namespace namespace #### #### I.8-e: Static Storage Duration static (deprecated register) #### #### I.8-f: Static Constant ####Expressive constexpr constinit (C++20) #### #### I.8-g: Thread Storage Duration thread_local #### #### I.8-h: Dynamic Storage Duration (new, new[], delete, delete[]) #### #### I.8-i: Automatic Storage Duration (no static, no thread_local, no new, no new[]) #### - biến tạo trong hàm thì tự tạo khi vào và tự xoá khi ra ```cpp! void hihi(){ int x=10;//tạo ra }//xoá ``` #### I.8-j: External Linkage (inline, extern) #### #### I.8-k: Internal Linkage #### #### I.8-l: No Linkage #### #### I.8-m: Block Scope {...} #### #### - biến tạo trong block thì tự tạo khi vào và tự xoá khi ra ```cpp! { int x=10;//tạo ra }//xoá ``` #### I.8-n: Class Struct Scope (Access Specifier: public:, private:, protected:) #### #### I.8-o: Lifetime #### ### I.9: Initialization ### #### I.9-a: Default Initialization int x; #### - khởi tạo biến không có giá trị ban đầu ```cpp! int x; ``` - nếu ngoài hàm main thì bằng 0 - nếu trong hàm main thì gía trị rác (số bất kỳ) #### I.9-b: Value Initialization int x{}; #### - để giá trị x=0 ```cpp! itn x{};//x=0; ``` #### I.9-c: Zero Initialization static int x; #### - tự động gán x=0 ```cpp! static int x;//x=0 ``` #### I.9-d: Copy Initialization int x = 0; #### - gán giá trị bằng dấu = ```cpp! int x=123; ``` #### I.9-e: Direct Initialization int x(0); #### #### I.9-f: Scalar List Initialization int x = {0}; (Narrowing Safe) #### #### .9-g: Copy List Initialization `vector<int> x = vector<int>{0, 0};` #### #### I.9-h: Direct List Initialization `vector<int> x{0, 0};` #### #### I.9-i: Initializer List Initialization `std::initializer_list<T> var = {..};` #### #### I.9-j: Reference Initialization int &x = dp[const_cat][const_card][const_cart]; #### #### I.9-k: Constant Initialization const int x = 0; #### #### I.9-l: Array Initialization int x[2]{}; #### #### I.9-m: Dynamic Initialization int *x = new int(0); (new) #### #### I.9-n: Zero-Fill Array Initialization int *x = new int[2](); (new[]) #### #### I.9-o: Dynamic Array Initialization int *x = new int[2]{0,0}; (new[]) #### #### I.9-p: Member Initialization struct Int { int member; Int(int param) : member(param) {} } #### #### I.9-q: Default Member Initialization struct Int{ int member = 0; } (NSDMI) #### #### I.9-r: String Literal Initialization const char name[] = "SPy"; (utf8, unicode, wchar, signed char, unsigned chah, char) #### #### I.9-s: Structured Binding Initialization for (auto [u, v] : edges) {} #### #### I.9-t: Control Flow Initialization if (int x = 0; x > 0) {} #### #### I.9-u: Partial Aggregate Initialization int x[5]{1, 2}; #### #### I.9-v: Direct Aggregate Initialization Pair p(1, 2); #### #### I.9-w: Designated Initialization Pair x = { .first = 1, .second = 2 }; (C++20) #### #### I.9-x: Designated Aggregate Initialization T object = { .var1 = arg1, .var2 { arg2 } } #### #### I.9-y: Lambda Capture Initialization auto test = [&bind=target](){}; #### #### I.9-z: Pointer Null Initialization int *ptr{}; #### ### I.10: Unary Operators ### #### I.10-a: +X Unary Plus #### giữ nguyên giá trị số (+)5 = 5 (+)-10 = -10 #### I.10-b: -X Unary Minus #### dùng để in ra số đối của số cần in 0(-)5 = -5 (-)-10 = 10 #### I.10-c: !X Negation #### là một toán tử hoặc phép logic dùng để đảo ngược giá trị của một biểu thức (!)true = false (!)false = true #### I.10-d: ~X Bitwise NOT #### đảo mỗi bit 0 thành 1, và mỗi bit 1 thành 0 (~)01001 = 10110 (~)1111 = 0000 #### I.10-e: ++X Pre Increment #### cộng trước, xử lý sau na=6; a[++na] truy cập phần tử thứ 7 sau đó na=7 #### I.10-f: --X Pre Decrement #### trừ trước, xử lý sau na=6; `a[--na]` truy cập phần tử thứ 5 sau đó na=5 #### I.10-g: X++ Post Increment #### xử lý trước, cộng sau na=6; a[na++] truy cập phần tử thứ 6 sau đó na=7 #### I.10-h: X++ Post Decrement #### xử lý trước, trừ sau na=6; `a[na--]`truy cập phần tử thứ 6 sau đó na=5 ### I.11 - Arithmetic Operators ### #### I.11-a: A+B Addition Plus #### cộng 2 số/chuỗi a=5,b=6 => c = a+b = 5+6 = 11 a="aa",b="bbb" => c= a+b = "aa"+"bbb" = "aabbb" #### I.11-b: A-B Subtraction Minus #### trừ 2 số a=6,b=2 => c = a-b = 6-2 = 4 a=4,b=10 =>c = a-b = 4-10 = -6 #### I.11-c: A*B Multiplication Multiply #### nhân 2 số a=2,b=3 => c = a*b = 2*3 = 6 #### I.11-d: A/B Division Div #### chia 2 số nguyên: a=6,b=2 => c = a/b = 6/2 = 3 thực: a=10.0,b=2.5 => c = a/b = 10/2.5 = 4 #### I.11-f: A+=B Assignment Addition #### gán a là tổng của a,b a=6,b=4 a += b a = a+b = 6+4 = 10 #### I.11-g: A-=B Assignment Subtraction #### gán a là hiệu của a,b a=6,b=4 a -= b a = a-b = 6-4 = 2 #### I.11-h: A*=B Assignment Multiplication #### gán a là tích của a,b a=6,b=4 a *= b a = a*b = 6*4 = 24 #### I.11-i: A/=B Assignment Division #### gán a là thương của a,b a=6,b=4 a /= b a = a/b = 6/4 = 1 #### I.11-j: A%=B Assignment Remainder #### gán a là a chia dư cho b a=6,b=4 a %= b a = a%b = 6%4 = 2 ### I.12 - Comparison Operators ### #### I.12-a: A<B Less LE #### kiểm tra a có nhỏ hơn b k ```cpp! int a=6,b=4; (a<b)=false a=4;b=6; (a<b)=true ``` #### I.12-b: A<=B Less Or Equal LEQ #### kiểm tra a có nhỏ hơn hoặc bằng b k ```cpp! int a=6,b=4; (a<=b)=false a=4;b=6; (a<=b)=true a=5;b=5; (a<=b)=true ``` #### I.12-c: A>B Greater GE #### kiểm tra a có lớn hơn b k ```cpp! int a=6,b=4; (a<b)=true a=4;b=6; (a<b)=false ``` #### I.12-d: A>=B Greater Or Equal GEQ #### kiểm tra a có lớn hơn hoặc bằng b k ```cpp! int a=6,b=4; (a<=b)=true a=4;b=6; (a<=b)=false int a=5,b=5 (a<=b)=true ``` #### I.12-e: A==B Equal EQ #### kiểm tra a bằng b k ```cpp! int a=4,b=6; (a= =b)=false a=5;b=5; (a= =b)=true ``` #### I.12-f: A!=B Not Equal NEQ #### kiểm tra a bằng b k ```cpp! int a=4,b=6; (a!=b)=true a=5;b=5; (a!=b)=false ``` #### I.12-g: A<=>B Three-way Spaceship Operator #### ### I.13: Logic Operators ### #### I.13-a: A&&B Logic And #### ```cpp! 0&&1=false 1&&1=true 0&&0=false ``` #### I.13-b: A||B Logic Or #### ```cpp! 0||1=true 1||1=true 0||0=false ``` #### I.13-c: There is no Logic Xor Operator #### #### I.13-d: Short Circuit #### ### I.14 - Bitwise Operators ### #### I.14-a: A<<B Shift Left #### nhân số đó với 2 số thập phân: 3<<1=6 số nhị phân: 0001<<1=0010 #### I.14-b: A>>B Shift Right #### chia số đó với 2 số thập phân: 10>>1=5 số nhị phân: 0110>>1=0011 #### I.14-c: A^B XOR #### ```cpp! (0^1)=true (1^0)=true (0^0)=false (1^1)=false ``` #### I.14-d: A&B AND #### ```cpp! (0&1)=false (1&0)=false (0&0)=false (1&1)=true ``` #### I.14-e: A|B OR #### ```cpp! (0|1)=true (1|0)=true (0|0)=false (1|1)=true ``` #### I.14-f: A<<=B Assignment Shift Left #### ```cpp! a=4 a<<=1 a=8 ``` #### I.14-g: A>>=B Assignment Shift Right #### ```cpp! a=4 a>>=1 a=2 ``` #### I.14-h: A^=B `Assignment XOR #### ```cpp! a=1 a^=0 a=1 ``` #### I.14-i: A&=B Assignment AND #### ```cpp! a=1 a&=0 a=0 ``` #### I.14-j: A|=B Assignment OR #### ```cpp! a=1 a|=0 a=1 ``` #### I.14-k: ~A UNARY NOT #### ```cpp! a=0111 b=~a=1000 ``` ### I.15 - Operator Overloadding ### #### I.15-a: Unoverloadable Operators ::, ., .*, ?: #### #### I.15-b: Custom Assignment Operator = #### #### I.15-c: Custom Function Call Operator () #### #### I.15-d: Custom Subscript Operator [] #### #### I.15-e: Custom Multidimensional Subscript Operator (comma operator, C++23 []) #### #### I.15-f: Custom Logic And Operator && #### #### I.15-g: Custom Logic And Operator || #### #### I.15-h: Custom Comma Operator , #### #### I.15-i: Custom Member Access Operator -> #### #### I.15-j: Custom Pointer Member Access Operator ->* #### #### I.15-k: Custom New Operator new new[] #### #### I.15-l: Custom Delete Operator delete delete[] #### #### I.15-m: User-defined Literals Operator ""_s() #### #### I.15-n: Explicit Conversion Operator explicit operator T() #### #### I.15-o: Boolean Explicit (Supressing Implicit Conversion) Operator explicit operator bool() #### #### I.15-z: Comparison Suite: strong ordering, partial ordering, poset #### ### I.16: Order ### #### i.16-a: Operator Prescedence #### trong ngoặc trước, đến *,/ xong đến +,-, từ trái sang phải ```cpp! a=5*(2+3)/2 a=5*6/2=30/2=15 ``` #### I.16-b: Evaluation Order #### #### I.16-c: Sequence Cases #### #### I.16-d: Assignment Sequence Points #### - thực hiện từ trái sang phải ```cpp! int a,b,c; a=b=c=0; ``` c=0, b=(c=0), a=(b=(c=0)) #### I.16-e: Function Call Arguments Order #### ### I.17: Enum ### #### I.17-a: Enum #### #### I.17-b: Enum Class #### #### I.17-c: Enum Size #### ### I.18: Template ### #### I.18-a: Generic #### #### I.18-y: TMP #### #### I.18-z: SFINAE #### ### I.19: Preprocessor ### #### I.19-a: #define #### - dùng để thay thế văn bản trước khi biên dịch ```cpp! #define abc int // ghi abc thì abc có nghĩa là int ``` #### I.19-b: #pragma #### #### I.19-c: File Guard #ifndef #ifdef #elif #endif #### #### I.19-d: Build Flags (-O2, -pipe, -static, -Wall, -Wextra) #### ### I.20: IO ### #### I.20-a: ios::sync_with_stdio(false); #### - tăng tốc độ nhập/xuất #### I.20-b: cin.tie(nullptr); #### - tăng tốc độ nhập xuất khi bạn không cần cout tự động flush trước mỗi lần đọc cin. #### I.20-c: cout.tie(nullptr); #### - ngắt liên kết cout với một stream khác. #### I.20-d: FastIO (getchar, putchar) #### - tăng tốc độ nhập xuất của stdin, stdout #### I.20-e: Unsafe FastIO (getchar_unlocked, putchar_unlocked) #### - nhanh nhưng không kiểm tra lock và không an toàn ### I.21 - Math ### #### I.21-a: abs() #### - trả về trị tuyệt đối của 1 số ```cpp! abs(5)=5 abs(-10)=10 ``` #### I.21-b: gcd() #### - trả về UCLN của 2 số ```cpp! int a=6,b=4; a=__gcb(a,b); //a=2 ``` #### I.21-c: lcm() #### - trả về BCNN của 2 số ```cpp! int a=6,b=4; a=__lcm(a,b); //a=12 ``` #### I.21-d: min() #### - trả về số nhỏ nhất trong 2 số ```cpp! int a=6,b=4; a=min(a,b); //a=4 ``` #### I.21-e: max() #### - trả về số lớn nhất trong 2 số ```cpp! int a=6,b=4; a=min(a,b); //a=6 ``` #### I.21-f: sqrt() #### - trả về căn bậc 2 của số đó ```cpp! int a=4; a=sqrt(a); //a=2 ``` #### I.21-g: pow() #### - trả về a mũ b ```cpp! int a=2,b=3; a=pow(a,b);//2^3 //a=8 ``` ### I.22 - Debug ### #### I.22-a: Runtime Assert #### #### I.22-b: Static Assert #### ### I.23 - Include ### #### I.23-a: <bits/stdc++.h> #### - Là một thư viện tổng hợp, gồm tất cả các thư viện chuẩn C++ #### I.23-b: Free Standing Library #### - được biên dịch và chạy trong môi trường không có hệ điều hành đầy đủ ## II. Implementation ## ### II.1 Bitmask ### #### II.1-a: IsZero #### kiểm tra coi số đó có = 0 hay không ```cpp! #include <iostream> using namespace std; bool IsZero(int x){ return !(x&(-x)); } int main(){ int n; cin>>n; if(IsZero(n)) cout<<0; else cout<<1; return 0; } ``` #### II.1-b: IsEven,IsOdd #### IsEven kiểm tra coi số đó có phải số chẵn không IsOdd kiểm tra coi số đó có phải số lẻ không ```cpp! #include <iostream> using namespace std; bool IsEven(int x){ return !(x&1); } bool IsOdd(int x){ return (x&1); } int main(){ int n; cin>>n; if(IsEven(n)) cout<<"chẵn"; if(IsOdd(n)) cout<<"lẻ"; return 0; } ``` #### II.1-c: IsPowerOfTwo #### kiểm tra xem số đó có phải là lũy thừa của 2 không ```cpp! #include <iostream> using namespace std; bool IsPowerOfTwo(int x){ int dem=0; while(x>0){ if(x&1) dem++; x=x>>1; } return(dem==1); } int main(){ int n; cin>>n; if(IsPowerOfTwo(n)) cout<<"YES"; else cout<<"NO"; return 0; } ``` #### II.1-d: Is Power Of Four/Is Power Of Power Of Two #### **IsPowerOfFour** kiểm tra xem 1 số có phải là lũy thừa của 4 hay không ```cpp! #include <iostream> using namespace std; bool IsPowerOfFour(int x){ while(x>0){ if(x&1) dem++; x=x>>2; } return (dem==1); } int main(){ int n; cin>>n; if(IsPowerOfFour(n)) cout<<"YES"; else cout<<"NO"; } ``` **IsPowerOfPowerOfTwo** kiểm tra xem một số có phải là lũy thừa của lũy thừa 2 hay không ```cpp! #include <iostream> using namespace std; bool IsPowerOfPowerOfTwo(long long x, long long k){ int dem=0; while(x>0){ if(x&1) dem++; x=x>>k; } return(dem==1); } int main(){ long long n,k; cin>>n>>k; } ``` #### II.1-e: CheckBit(X, B) SetBit(X, B) UnsetBit(X, B) ToggleBit(X, B) #### ```cpp! bool CheckBit(int x, int b){ return (b>>(x-1)&1); } ``` #### II.1-f: AssignBit(X, B, V) #### #### II.1-g: ToBinary(X) #### #### II.1-h: ToOctet(X) ToHex(X) #### #### II.1-i: XorSwap(X, Y) #### #### II.1-j: BitLength(X) Log2(X) #### #### II.1-k: CountSetBit(X) CountUnsetBit(X) #### #### II.1-l: CountTrailingZero(X) CountTrailingOne(X) #### #### II.1-m: CountLeadingZero(X) CountLeadingOne(X) #### #### II.1-n: LeastSignificantBit(X) MostSignificantBit(X) #### #### II.1-o: BitLeftRotation(X, N) BitRightRotation(X, N) #### #### II.1-p: SubmaskEnumeration(X) #### #### II.1-q: SignOf(X) IsPositive(X) IsNegative(X) #### ```cpp! bool IsPositive(int x){ return (x>0) } bool IsNegative(int x){ return (x<0) } ``` #### II.1-r: HasOppositeSign(X, Y) #### #### II.1-t: BitAbs(X) #### #### II.1-u: BitMin(X, Y) BitMax(X, Y) #### #### II.1-v: LexicoNextBitPermutation(X) LexicoPrevBitPermutation(X) #### #### II.1-w: NextPowerOfTwo(X) PrevPowerOfTwo(X) #### #### II.1-x: GrayCode(X) InverseGrayCode(X) #### #### II.1-x: ReverseBit(X) #### #### II.1-z: GenAllBinary(N) GenAllTernary(N) GenAllQuaternary(N) GenAllGrayCode(N) #### ### II.2: Bitmask Bultin ### #### II.2-a: Count Set Bit __builtin_popcount**(X) (**=NULL,L,LL) #### #### II.2-b: Count Trailing Zeros __builtin_ctz**(X) (**=NULL,L,LL) #### #### II.2-c: Count Leading Zeros __builtin_clz**(X) (**=NULL,L,LL) #### #### II.2-d: Parity Check __builtin_parity**(X) (**=NULL,L,LL) #### #### II.2-e: Least Significant Setbit __builtin_ffs**(X) (**=NULL,L,LL) #### #### II.2-f: Bit Left Rotation __builtin_rotateleft**(X, N) (**=8,16,32,64) #### #### II.2-g: Bit Right Rotation __builtin_rotateright**(X, N) (**=8,16,32,64) #### #### II.2-h: Bit Swap Endians __builtin_bswap**(X) (**=8,16,32,64) #### ## I. DailyChallenge 1/11 ## ### Làm sao để đếm thời gian chương trình chạy ### - tìm ra thời gian thực hiện của các phần khác nhau của chương trình bằng cách sử dụng thư viện std::chrono trong C++ 11. - std::chrono có hai đối tượng riêng biệt - timepoint và duration. Timepoint và duration đại diện cho một điểm, khoảng thời gian. - Thư viện C++ cho phép chúng ta trừ hai điểm thời gian để có được khoảng thời gian giữa hai điểm thời gian đó. - Sử dụng các phương thức được cung cấp, chúng ta cũng có thể chuyển đổi khoảng thời gian này sang các đơn vị thích hợp. ### Các kiểu đồng hồ (clock) để đếm thời gian chương trình chạy ### - Một đối tượng thời lượng thể hiện khoảng thời gian bằng cách đếm số như một phút, hai giờ,.. Ví dụ, "42 giây" có thể được biểu thị bằng một khoảng thời gian bao gồm 42 tích tắc của một đơn vị thời gian 1 giây. - Đồng hồ bao gồm một điểm bắt đầu (hay kỷ nguyên) và một nhịp tích tắc. Ví dụ, một đồng hồ có thể có kỷ nguyên là ngày 22 tháng 2 năm 1996 và mỗi giây tích tắc. C++ định nghĩa ba kiểu đồng hồ: - steady_clock: là đồng hồ đơn điệu, không được điều chỉnh. Nó chạy với tốc độ đều đặn. Nó được viết là std::chrono::steady_clock - system_clock: là thời gian hiện tại theo hệ thống (đồng hồ thông thường mà chúng ta thấy trên máy tính). Nó được viết là std::chrono::system_clock - high_resolution_clock: Cung cấp chu kỳ tick nhỏ nhất có thể. Nó được viết là: std::chrono::high_resolution_clock | Kiểu đồng hồ| Điểm chung| Điểm riêng| |-|-|-| | steady_clock|| Đo khoảng thời gian (như đồng hồ bấm giờ)| |system_clock|Cả ba đều cung cấp một kiểu thời gian (time_point) và một đơn vị thời gian (duration), cho phép thực hiện các phép tính thời gian như tính toán khoảng thời gian, chênh lệch thời gian và chuyển đổi giữa các đơn vị thời gian.|Thời gian đồng hồ treo tường (ngày giờ thực)| |high_resolution_clock||Biểu thị đồng hồ có chu kỳ tích tắc nhỏ nhất do triển khai cung cấp. Nó có thể là một bí danh của std::chrono::system_clock hoặc std::chrono::steady_clock , hoặc một đồng hồ thứ ba, độc lập.| *Chú thích: bí danh (hay alias), là một cách đặt tên mới cho một kiểu dữ liệu đã tồn tại, giúp code dễ đọc hơn, đặc biệt với các kiểu phức tạp* ### Nhận xét ### :::success Cả steady_clock lẫn system_clock đều không đi kèm với bất kỳ đảm bảo nào về độ phân giải, vì vậy high_resolution_clock đóng vai trò hữu ích bằng cách cho phép nhà cung cấp cung cấp loại đồng hồ có độ phân giải cao nhất của nền tảng, trong trường hợp cả steady_clock và system_clock đều không phải là loại đó. Tuy nhiên, vì tiêu chuẩn cho phép high_resolution_clock có thể là một bí danh (alias) của steady_clock hoặc system_clock, nên việc sử dụng nó làm tăng sự không chắc chắn cho chương trình mà không mang lại lợi ích gì. ::: :::spoiler code cho steady_clock ```cpp! #include <iostream> #include <ctime> #include <ratio> #include <chrono> int main () { using namespace std::chrono; steady_clock::time_point t1 = steady_clock::now(); std::cout << "printing out 1000 stars...\n"; for (int i=0; i<1000; ++i) std::cout << "*"; std::cout << std::endl; steady_clock::time_point t2 = steady_clock::now(); duration<double> time_span = duration_cast<duration<double>>(t2 - t1); std::cout << "It took me " << time_span.count() << " seconds."; std::cout << std::endl; return 0; } ``` ::: :::spoiler code cho system_clock ```cpp! #include <iostream> #include <ctime> #include <ratio> #include <chrono> int main () { using std::chrono::system_clock; std::chrono::duration<int,std::ratio<60*60*24> > one_day (1); system_clock::time_point today = system_clock::now(); system_clock::time_point tomorrow = today + one_day; std::time_t tt; tt = system_clock::to_time_t ( today ); std::cout << "today is: " << ctime(&tt); tt = system_clock::to_time_t ( tomorrow ); std::cout << "tomorrow will be: " << ctime(&tt); return 0; } ``` ::: :::spoiler code cho high_resolution_clock ```cpp! #include <iostream> #include <chrono> int main() { std::cout << "Bat dau cong viec..." << std::endl; // --- BƯỚC 1: Lấy thời điểm bắt đầu --- auto start = std::chrono::high_resolution_clock::now(); // --- BƯỚC 2: Mô phỏng một công việc (ví dụ: một vòng lặp tốn thời gian) --- // Sử dụng volatile để ngăn trình biên dịch tối ưu hóa loại bỏ vòng lặp này volatile double result = 0; for (long long i = 0; i < 100000000; ++i) { result += std::hash<long long>{}(i) % 100; // Một phép tính đơn giản } // --- BƯỚC 3: Lấy thời điểm kết thúc --- auto end = std::chrono::high_resolution_clock::now(); std::cout << "Ket thuc cong viec." << std::endl; // In ra kết quả để đảm bảo vòng lặp không bị tối ưu hóa hoàn toàn std::cout << "Ket qua tam tinh: " << result << std::endl; // --- BƯỚC 4: Tính toán khoảng thời gian (duration) --- // Sử dụng duration_cast để chuyển đổi khoảng thời gian sang mili giây (kiểu integer) auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); // --- BƯỚC 5: In kết quả --- std::cout << "Thoi gian thuc thi: " << duration_ms.count() << " ms" << std::endl; // Bạn cũng có thể in ra dưới dạng giây với độ chính xác cao hơn (kiểu double) std::chrono::duration<double> duration_seconds = end - start; std::cout << "Thoi gian thuc thi chinh xac hon: " << duration_seconds.count() << " s" << std::endl; return 0; } ``` ::: ## I.DailyChallenge 4/11 ## ### Bài 1: Square String? 1619A ### - dùng `using namespace std` ```cpp! #include <iostream> #include <string> using namespace std; bool check(string s){ if(s.size()%2==1) return false; int i=0,j=s.size()/2; while(j<s.size()){ if(s[i]!=s[j]){ return false; } i++;j++; } return true; } int main() { ios::sync_with_stdio(0); cin.tie(0); int t; cin>>t; while(t--){ string s; cin>>s; if(check(s)) cout<<"YES\n"; else cout<<"NO\n"; } return 0; } ``` - không dùng `using namespace std`; ```cpp! #include <iostream> #include <string> bool check(std::string s){ if(s.size()%2==1) return false; int i=0,j=s.size()/2; while(j<s.size()){ if(s[i]!=s[j]){ return false; } i++;j++; } return true; } int main() { std::ios::sync_with_stdio(0); std::cin.tie(0); int t; std::cin>>t; while(t--){ std::string s; std::cin>>s; if(check(s)) std::cout<<"YES\n"; else std::cout<<"NO\n"; } return 0; } ``` ![image](https://hackmd.io/_uploads/HkN0VBPJWg.png) ### Bài 2: Magnet 334A ### - dùng `using namespace std` ```cpp! #include <iostream> using namespace std; const int mx=100000; int a[mx]; int main() { int n; cin>>n; for(int i=0; i<n; i++){ cin>>a[i]; } int dem=1; for(int i=0; i<n-1; i++){ if(a[i]!=a[i+1]) dem++; } cout<<dem; return 0; } ``` - không dùng `using namespace std` ```cpp! #include <iostream> const int mx=100000; int a[mx]; int main() { int n; std::cin>>n; for(int i=0; i<n; i++){ std::cin>>a[i]; } int dem=1; for(int i=0; i<n-1; i++){ if(a[i]!=a[i+1]) dem++; } std::cout<<dem; return 0; } ``` ![image](https://hackmd.io/_uploads/SyFV6HP1-g.png) ### Bài 3: Sum 1742A ### - dùng `using namespace std` ```cpp! #include <iostream> using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(0);cout.tie(0); int n; cin>>n; while(n--){ int a,b,c; cin>>a>>b>>c; if(a+b==c) cout<<"YES"; else if(a+c==b) cout<<"YES"; else if(b+c==a) cout<<"YES"; else cout<<"NO"; cout<<"\n"; } return 0; } ``` - không dùng `using namespace std` ```cpp! #include <iostream> int main() { std::ios_base::sync_with_stdio(0); std::cin.tie(0); int n;std::cin>>n; while(n--){ int a,b,c; std::cin>>a>>b>>c; if(a+b==c) std::cout<<"YES"; else if(a+c==b) std::cout<<"YES"; else if(b+c==a) std::cout<<"YES"; else std::cout<<"NO"; std::cout<<"\n"; } return 0; } ``` ### using namespace std ### - giúp code ngắn gọn hơn, thay vì viết `std::cout<<"YES";`, `std::cin>>a;`,.. thì chúng ta có thể viết `cout<<"YES";`, `cin>>a;`,... - nhưng sẽ khó đọc trong chương trình lớn vì có thể trùng tên với một hàm nào đó, hay sẽ gây rối và khó đọc vì có nhiều hàm, biến,..Từ đó gây rối và khó sửa lỗi trong phần code - Vì vậy, `using namespace std` phù hợp trong việc làm bài tập, code ngắn, hay làm thi lập trình - Khi làm các chương trình lớn, hay code các dự án của các tổ chức nhỏ, lớn thì không nên sử dụng `using namespace std`. ## I. DailyChallenge 5/11 ## ### Bài: Candies And Two Sisters 1335A ### - code sử dụng hàm ```cpp! #include <iostream> #include <cmath> using namespace std; int main() { int t; cin >> t; while (t--) { double n; cin >> n; cout <<(int)round(n/2)-1<<"\n"; } return 0; } ``` - code tự xây hàm ```cpp! #include <iostream> using namespace std; int fun(double n) { int pn = (int)n; double ptp = n - pn; if (ptp >= 0.5) { return pn + 1; } return pn; } int main() { int t; cin >> t; while (t--) { double n; cin >> n; cout << fun(n / 2) - 1 << "\n"; } return 0; } ``` ### Bài: Elephant 617A ### - code dùng hàm ```cpp! #include <iostream> #include <cmath> using namespace std; int main() { double x; cin >> x; cout << (int)ceil(x / 5.0); return 0; } ``` - code tự xây hàm ```cpp! #include <iostream> using namespace std; int fun(double x) { int pn = (int)x; if (x == pn) { return pn; } else { return pn + 1; } } int main() { double x; cin >> x; cout << fun(x / 5.0); return 0; } ``` ### Bài: Soildiers and Bananas 546A ### - code dùng hàm ```cpp! #include <iostream> #include <cmath> using namespace std; int main() { int k; int n; int w; cin >> k >> n >> w; int tong = k * w * (w + 1) / 2; int muon = max(0, tong - n); cout << muon; return 0; } ``` - code tự xây hàm ```cpp! #include <iostream> using namespace std; int lonnhat(int x, int y) { if (x > y) { return x; } else { return y; } } int main() { int k; int n; int w; cin >> k >> n >> w; int tong = k * w * (w + 1) / 2; int muon = lonnhat(0, tong - n); cout << muon; return 0; } ``` ### Nhận Xét ### - Ưu điểm: Dễ hiểu, dễ tuỳ biến theo đề bài - Nhược điểm: Không tối ưu và nhanh bằng max(), không thể tự động xử lý loại dữ liệu khác ngoài int ## I. DailyChallenge 6/11 ## - Chuẩn C++ quy định đơn vị nhỏ nhất có thể địa chỉ hoá được trong bộ nhớ là 1 byte, chứ không phải 1 bit. Nói cách khác: - CPU và RAM chỉ có thể đọc/ghi dữ liệu theo địa chỉ byte, không theo bit riêng lẻ. - Mỗi biến trong C++ phải có địa chỉ duy nhất, và địa chỉ đó trỏ tới ít nhất 1 byte. ### Giải thích ### - Phần cứng giới hạn RAM được chia theo từng ô nhớ có kích thước 8 bit (1 byte). CPU khi truy cập bộ nhớ sẽ đọc/ghi theo byte hoặc bội số của nó (2, 4, 8 byte...). Không có lệnh CPU nào đọc “bit thứ 3 của byte 57”. - Chuẩn ngôn ngữ Trong C++, sizeof(char) luôn bằng 1 byte — và đó là đơn vị nhỏ nhất có thể lưu trữ và định danh địa chỉ. Không có kiểu dữ liệu nào nhỏ hơn char. ### Giải pháp thay thế: ### Nếu chỉ muốn tiết kiệm bộ nhớ, ta nén bit thủ công — ví dụ, dùng `std::bitset<N>` hoặc `std::vector<bool>`. Chúng không tạo biến 1 bit thật, mà gói nhiều bit chung trong 1 byte hoặc nhiều byte và xử lý qua toán tử bit. ### Nhận xét ### Tóm lại, không có kiểu 1 bit vì phần cứng không hỗ trợ truy cập cấp bit. Byte là đơn vị nhỏ nhất có thể được định địa chỉ và xử lý trực tiếp. ## I. DailyChallenge 7/11 ## ### Có thể nhét thêm tham số nào vào hàm main không? ### Có, chúng ta hoàn toàn có thể thêm tham số vào hàm `main`, nhưng không giống như các hàm thông thường. ### Có thể sử dụng tham số nào không? ### - `main()` chỉ chấp nhận các tham số: - `int argc` - `char* argv[]` ### Những tham số quen thuộc của hàm main() là gì? ### - không có ```cpp! int main()//void { // code return 0; } ``` - có 2 tham số argc, argv ```cpp! int main(int argc, char* argv[])//char**argv[] { // code return 0; } ``` ### Nhận xét ### argv và argc là cách các đối số dòng lệnh được truyền vào hàm main() trong ngôn ngữ C và C++. argc sẽ là số lượng chuỗi được trỏ tới bởi argv. Trên thực tế, con số này thường là 1 cộng với số lượng đối số, vì hầu hết các trình biên dịch đều thêm tên của chương trình vào đầu mảng. Các biến này được đặt tên là argc (số lượng đối số) và argv (mảng đối số) theo quy ước, nhưng bạn hoàn toàn có thể đặt bất kỳ tên hợp lệ nào khác. Chú thích: Đối số dòng lệnh (command-line arguments) là những giá trị mà bạn truyền vào chương trình khi chạy nó từ dòng lệnh (terminal hoặc command prompt). Chúng cho phép người dùng tùy chỉnh cách chương trình hoạt động mà không cần thay đổi mã nguồn.