Level 1 - Cơ Bản / Basics

Bài Tập 1: Ba Ký Tự Đầu (First Three Characters)

Đề bài: Đọc một từ và in 3 ký tự đầu tiên của nó.

Problem: Read a word and print its first 3 characters.

Ví dụ:

Programming

Output:

Pro

Bài Tập 2: Đảo Ngược Chuỗi (Reverse a String)

Đề bài: Đọc một từ và in nó theo thứ tự ngược lại.

Problem: Read a word and print it backwards.

Ví dụ:

Python

Output:

nohtyP

Bài Tập 3: Xây Map Tên Và Tuổi (Build a Name-Age Map)

Đề bài: Đọc 3 cặp tên và tuổi vào một map, rồi đọc thêm một tên và in tuổi tương ứng.

Problem: Read 3 name-age pairs into a map, then read one more name and print its age.

Ví dụ:

Alice 14
Bob 15
Chi 13
Bob

Output:

Bob: 15

Bài Tập 4: Nhỏ Nhất Và Lớn Nhất (Min and Max)

Đề bài: Đọc N số nguyên rồi in giá trị nhỏ nhất và lớn nhất trong dãy.

Problem: Read N integers, then print the smallest and the largest value in the list.

Ví dụ:

6
15 42 8 23 4 16

Output:

Min: 4
Max: 42

Bài Tập 5: Kiểm Tra Khóa Tồn Tại (Check if a Key Exists)

Đề bài: Cho sẵn map ages với Alice = 14 và Bob = 15. Đọc một tên; nếu có thì in tuổi, ngược lại in "Not found".

Problem: Given a map ages with Alice = 14 and Bob = 15, read a name. If it exists print the age, otherwise print "Not found".

Ví dụ:

Dan

Output:

Not found

Level 2 - Trung Bình / Intermediate

Bài Tập 6: Đếm Số Lần Xuất Hiện Của Từ (Word Count)

Đề bài: Đọc các từ cho tới hết dữ liệu vào và đếm số lần mỗi từ xuất hiện.

Problem: Read words until the input ends and count how many times each word appears.

Ví dụ:

the cat sat on the mat

Output:

cat: 1
mat: 1
on: 1
sat: 1
the: 2

Bài Tập 7: Các Từ Bắt Đầu Bằng Một Chữ Cái (Words Starting With a Letter)

Đề bài: Dòng đầu là một chữ cái, các dòng sau là các từ. In những từ bắt đầu bằng chữ cái đó và tổng số từ tìm được.

Problem: The first input is a letter, the rest are words. Print every word starting with that letter and the total count found.

Ví dụ:

b
banana bread and butter

Output:

banana
bread
butter
Count: 3

Bài Tập 8: Học Sinh Điểm Cao Nhất (Best Student)

Đề bài: Đọc 3 cặp tên và điểm, rồi in ra ai đạt điểm cao nhất và điểm là bao nhiêu.

Problem: Read 3 name-score pairs, then print who scored the highest and what that score was.

Ví dụ:

Linh 7
Nam 8
Chi 9

Output:

Best: Chi (9)

Bài Tập 9: Căn Thẳng Hóa Đơn (Align the Receipt)

Đề bài: Đọc N món, mỗi món gồm tên và giá (số nguyên). In mỗi món trên một dòng rộng ĐÚNG 20 ký tự: tên ở đầu dòng, giá ở cuối dòng, khoảng giữa lấp đầy bằng dấu chấm.

Problem: Read N items, each with a name and an integer price. Print each item on a line EXACTLY 20 characters wide: the name at the start, the price at the end, and the gap between them filled with dots.

Ví dụ:

3
Apple 25000
Bread 12000
Milk 5000

Output:

Apple..........25000
Bread..........12000
Milk............5000

Bài Tập 10: Bỏ Điểm Thấp Nhất (Drop the Lowest Score)

Đề bài: Đọc N điểm số. Bỏ đi MỘT điểm thấp nhất, rồi in điểm trung bình của những điểm còn lại.

Problem: Read N scores. Drop ONE lowest score, then print the average of the scores that remain.

Ví dụ:

5
8 9 10 7 7

Output:

Average: 8.5

Level 3 - Nâng Cao / Advanced

Bài Tập 11: Từ Xuất Hiện Nhiều Nhất (Most Frequent Word)

Đề bài: Đọc các từ tới hết dữ liệu vào và in ra từ xuất hiện nhiều nhất cùng số lần.

Problem: Read words until the input ends and print the word that appears most often with its count.

Ví dụ:

the cat sat on the mat the end

Output:

Most frequent: the (3)

Bài Tập 12: Kiểm Tra Chuỗi Đối Xứng (Palindrome Check)

Đề bài: Đọc một dòng; bỏ khoảng trắng và không phân biệt hoa thường, in "Yes" nếu đọc xuôi ngược giống nhau, ngược lại in "No".

Problem: Read a line; ignoring spaces and letter case, print "Yes" if it reads the same forwards and backwards, otherwise print "No".

Ví dụ:

Never odd or even

Output:

Yes

Bài Tập 13: Tính Tiền Giỏ Hàng (Shopping Cart Total)

Đề bài: Cho bảng giá apple = 5000, bread = 12000, milk = 20000. Đọc số món cần mua, rồi mỗi món gồm tên và số lượng; in thành tiền từng dòng và tổng cộng.

Problem: Given prices apple = 5000, bread = 12000, milk = 20000, read how many items are bought, then each item's name and quantity; print each line total and the grand total.

Ví dụ:

2
apple 3
bread 1

Output:

apple x3 = 15000
bread x1 = 12000
Total: 27000

ĐÁP ÁN / SOLUTIONS

Level 1 - Đáp Án

Solution 1: Ba Ký Tự Đầu

Giải thích: substr(0, 3) cắt từ chỉ số 0 và lấy 3 ký tự — tham số thứ hai là ĐỘ DÀI, không phải vị trí kết thúc.

Explanation: substr(0, 3) cuts from index 0 and takes 3 characters — the second argument is a LENGTH, not an end position.

Code:

cpp
#include <iostream> #include <string> using namespace std; int main() { string word; cin >> word; cout << word.substr(0, 3) << endl; return 0; }

Solution 2: Đảo Ngược Chuỗi

Giải thích: Không có slicing trong C++, nên phải viết vòng lặp đi ngược qua từng chỉ số.

Explanation: C++ has no slicing, so a loop walking the indexes backwards does the job.

Code:

cpp
#include <iostream> #include <string> using namespace std; int main() { string word; cin >> word; for (int i = word.size() - 1; i >= 0; i--) { cout << word[i]; } cout << endl; return 0; }

Solution 3: Xây Map Tên Và Tuổi

Giải thích: Gán vào một khóa chưa tồn tại sẽ tạo cặp mới; gán lại khóa cũ sẽ thay giá trị.

Explanation: Assigning to a key that does not exist creates a new pair; assigning to an existing key replaces its value.

Code:

cpp
#include <iostream> #include <map> #include <string> using namespace std; int main() { map<string, int> ages; for (int i = 0; i < 3; i++) { string name; int age; cin >> name >> age; ages[name] = age; } string who; cin >> who; cout << who << ": " << ages[who] << endl; return 0; }

Solution 4: Nhỏ Nhất Và Lớn Nhất

Giải thích: Khởi tạo bằng phần tử đầu là an toàn nhất, vì nó chắc chắn thuộc dữ liệu.

Explanation: Seeding with the first element is the safe start, because it is guaranteed to be real data.

Code:

cpp
#include <iostream> #include <vector> using namespace std; int main() { int n; cin >> n; vector<int> nums; for (int i = 0; i < n; i++) { int x; cin >> x; nums.push_back(x); } int minValue = nums[0]; int maxValue = nums[0]; for (int x : nums) { if (x < minValue) minValue = x; if (x > maxValue) maxValue = x; } cout << "Min: " << minValue << endl; cout << "Max: " << maxValue << endl; return 0; }

Solution 5: Kiểm Tra Khóa Tồn Tại

Giải thích: Khác Python, truy cập map[khóa-chưa-có] KHÔNG báo lỗi mà lặng lẽ tạo khóa với giá trị 0 — vì vậy phải dùng count.

Explanation: Unlike Python, map[missing-key] does NOT error — it silently creates the key with value 0, which is why count is used first.

Code:

cpp
#include <iostream> #include <map> #include <string> using namespace std; int main() { map<string, int> ages = {{"Alice", 14}, {"Bob", 15}}; string name; cin >> name; if (ages.count(name)) { cout << name << ": " << ages[name] << endl; } else { cout << "Not found" << endl; } return 0; }

Level 2 - Đáp Án

Solution 6: Đếm Số Lần Xuất Hiện Của Từ

Giải thích: counts[word]++ tận dụng việc map tự tạo giá trị 0 cho khóa mới; std::map luôn in theo thứ tự khóa.

Explanation: counts[word]++ relies on the map creating a 0 for a new key; std::map always prints in key order.

Code:

cpp
#include <iostream> #include <map> #include <string> using namespace std; int main() { map<string, int> counts; string word; while (cin >> word) { counts[word]++; } for (auto& [w, n] : counts) { cout << w << ": " << n << endl; } return 0; }

Solution 7: Các Từ Bắt Đầu Bằng Một Chữ Cái

Giải thích: C++ không có startswith, nhưng so sánh word[0] là đủ khi chỉ cần kiểm tra một ký tự.

Explanation: C++ has no startswith, but comparing word[0] is enough when only one character matters.

Code:

cpp
#include <iostream> #include <string> using namespace std; int main() { char letter; cin >> letter; int count = 0; string word; while (cin >> word) { if (word[0] == letter) { cout << word << endl; count++; } } cout << "Count: " << count << endl; return 0; }

Solution 8: Học Sinh Điểm Cao Nhất

Giải thích: map sắp xếp theo KHÓA chứ không theo giá trị, nên muốn tìm điểm cao nhất vẫn phải duyệt hết.

Explanation: A map is sorted by KEY, not by value, so finding the highest score still needs a full pass.

Code:

cpp
#include <iostream> #include <map> #include <string> using namespace std; int main() { map<string, int> scores; for (int i = 0; i < 3; i++) { string name; int score; cin >> name >> score; scores[name] = score; } string bestName = ""; int bestScore = -1; for (auto& [name, score] : scores) { if (score > bestScore) { bestScore = score; bestName = name; } } cout << "Best: " << bestName << " (" << bestScore << ")" << endl; return 0; }

Solution 9: Căn Thẳng Hóa Đơn

Giải thích: Muốn căn thẳng thì phải biết giá CHIẾM bao nhiêu ký tự — to_string biến số thành chuỗi để đo được bằng .size(), điều mà cout << price không cho biết.

Explanation: Aligning needs the WIDTH of the price, not its value — to_string turns the number into a string so .size() can measure it, which cout << price never reveals.

Code:

cpp
#include <iostream> #include <string> using namespace std; int main() { int n; cin >> n; for (int i = 0; i < n; i++) { string name; int price; cin >> name >> price; string priceText = to_string(price); int dots = 20 - (int)name.size() - (int)priceText.size(); cout << name; for (int j = 0; j < dots; j++) { cout << "."; } cout << priceText << endl; } return 0; }

Solution 10: Bỏ Điểm Thấp Nhất

Giải thích: Chỉ trừ MỘT lần giá trị nhỏ nhất: ví dụ trên có hai điểm 7, bỏ một điểm thì điểm 7 còn lại vẫn được tính.

Explanation: The lowest value is subtracted only ONCE: the example has two 7s, and dropping one still leaves the other 7 counting towards the average.

Code:

cpp
#include <iostream> #include <vector> using namespace std; int main() { int n; cin >> n; vector<int> scores; for (int i = 0; i < n; i++) { int x; cin >> x; scores.push_back(x); } int sum = 0; int lowest = scores[0]; for (int x : scores) { sum += x; if (x < lowest) lowest = x; } double average = (double)(sum - lowest) / (n - 1); cout << "Average: " << average << endl; return 0; }

Level 3 - Đáp Án

Solution 11: Từ Xuất Hiện Nhiều Nhất

Giải thích: Vì map duyệt theo thứ tự khóa và ta dùng > (không phải >=), khi hòa số lần thì từ đứng trước bảng chữ cái được giữ.

Explanation: Because the map iterates in key order and the test is > (not >=), a tie keeps the alphabetically earlier word.

Code:

cpp
#include <iostream> #include <map> #include <string> using namespace std; int main() { map<string, int> counts; string word; while (cin >> word) { counts[word]++; } string bestWord = ""; int bestCount = 0; for (auto& [w, n] : counts) { if (n > bestCount) { bestCount = n; bestWord = w; } } cout << "Most frequent: " << bestWord << " (" << bestCount << ")" << endl; return 0; }

Solution 12: Kiểm Tra Chuỗi Đối Xứng

Giải thích: Chuẩn hóa trước (bỏ khoảng trắng, về chữ thường) rồi mới so sánh; toán tử == so sánh nội dung hai string.

Explanation: Normalize first (drop spaces, lowercase), then compare; == compares the contents of two strings.

Code:

cpp
#include <iostream> #include <string> using namespace std; int main() { string line; getline(cin, line); string clean = ""; for (char c : line) { if (c != ' ') { clean += tolower(c); } } string reversed = ""; for (int i = clean.size() - 1; i >= 0; i--) { reversed += clean[i]; } if (clean == reversed) { cout << "Yes" << endl; } else { cout << "No" << endl; } return 0; }

Solution 13: Tính Tiền Giỏ Hàng

Giải thích: map chỉ dùng để TRA giá; thứ tự in là thứ tự đọc vào vì ta in ngay trong vòng lặp.

Explanation: The map is only used to LOOK UP prices; the print order is the input order because printing happens inside the loop.

Code:

cpp
#include <iostream> #include <map> #include <string> using namespace std; int main() { map<string, int> prices = {{"apple", 5000}, {"bread", 12000}, {"milk", 20000}}; int n; cin >> n; int total = 0; for (int i = 0; i < n; i++) { string item; int qty; cin >> item >> qty; int line = prices[item] * qty; total += line; cout << item << " x" << qty << " = " << line << endl; } cout << "Total: " << total << endl; return 0; }