Bài 14: Tổng ôn series Nhập môn lập trình và đề thi thử 6 câu có lời giải chi tiết (C++ và Python)
Lời mở đầu
Chúc mừng em đã đi tới bài cuối của series Nhập môn lập trình! Sau 13 bài, em đã có trong tay gần như đủ “đồ nghề” để giải các câu dễ và trung bình của một đề thi học sinh giỏi cấp huyện, cấp tỉnh hay đề thi vào lớp 10 chuyên Tin. Bài này không dạy kiến thức mới mà giúp em ghép các mảnh lại với nhau: một sơ đồ tổng kết, quy trình 6 bước khi làm một bài thi, và quan trọng nhất là một đề thi thử 6 câu trải đều các chủ đề đã học. Hãy làm thật nghiêm túc: bấm giờ 180 phút, không xem gợi ý, tự chấm bằng các ví dụ rồi mới so với lời giải.
Lộ trình bài viết, bấm vào từng phần để nhảy tới:
Phần 1Sơ đồ kiến thức của series
14 bài của series chia thành 4 nhóm. Mỗi nhóm dựa trên nhóm trước nó; nếu thấy hổng ở đâu, em hãy quay lại đúng bài đó (bấm vào thanh series phía trên để mở nhanh).
Nền tảng → Tổ chức dữ liệu → Kỹ năng thi → Các kỹ thuật thuật toán đầu tiên.
| Dạng đề hay gặp | Kiến thức cần | Bài |
|---|---|---|
| Tính toán theo công thức, bậc thang, phân loại | Nhập xuất, kiểu số, if – else | 2, 3 |
| Đếm, tính tổng, xử lý chữ số | Vòng lặp, % và / | 4, 12 |
| Xử lý dãy số: max, min, tìm kiếm, sắp xếp | Mảng, sort, tìm kiếm nhị phân | 6, 10 |
| Bảng, lưới, bản đồ | Mảng 2 chiều | 7 |
| Chuẩn hóa xâu, đếm từ, đối xứng | string, getline, mã ASCII | 8 |
| Danh sách nhiều thuộc tính, xếp hạng | struct, hàm so sánh cmp | 10 |
| Loại trùng, đếm tần suất, ngoặc, hàng đợi | set, map, stack, queue | 11, 13 |
| Ước, UCLN, nguyên tố | Euclid, $O(\sqrt n)$, sàng | 12 |
| Nhiều câu hỏi về đoạn $[l, r]$ | Mảng cộng dồn, mảng hiệu | 13 |
Phần 2Quy trình 6 bước khi làm một bài thi
- Đọc kỹ đề, đọc hai lần. Gạch chân dữ liệu vào, dữ liệu ra, tên file, và đặc biệt là giới hạn ($n$ tối đa, giá trị lớn nhất).
- Tự làm ví dụ bằng tay. Nếu chưa tính tay ra đúng đáp án ví dụ thì chưa hiểu đề, đừng vội code.
- Chọn thuật toán theo giới hạn (bảng tra ở bài 9). Ước lượng số phép tính trước khi code. Nếu chỉ nghĩ được cách chậm, vẫn nên code nó để lấy điểm các test nhỏ.
- Code theo khung chuẩn:
bits/stdc++.h,freopen, tăng tốc nhập xuất,long long. - Thử với ví dụ và các test đặc biệt tự nghĩ: $n = 1$, mọi số bằng nhau, số âm, số 0, giá trị lớn nhất.
- Rà checklist bên dưới rồi mới nộp. Thi thật thường chỉ được nộp một lần!
Phần 3Đề thi thử nhập môn: 6 câu, 180 phút
Đề gồm 6 câu, tổng 20 điểm, mỗi câu chấm theo bộ test. Dữ liệu đọc từ bàn phím, ghi ra màn hình (khi luyện đề thi thật có file, hãy tự thêm freopen). Ngôn ngữ C++ hoặc Python. Gợi ý và code tham khảo được thu gọn, chỉ mở ra sau khi đã tự làm.
| Câu | Tên bài | Chủ đề | Điểm |
|---|---|---|---|
| 1 | Tiền điện | Rẽ nhánh, tính toán | 3 |
| 2 | Số tròn chục chữ số | Vòng lặp, chữ số | 3 |
| 3 | Chuẩn hóa họ tên | Xâu ký tự | 3 |
| 4 | Bảng xếp hạng bóng đá | Struct, sắp xếp nhiều tiêu chí | 3 |
| 5 | Ngày nắng nóng | Mảng cộng dồn | 4 |
| 6 | Tổng nguyên tố trên đoạn | Sàng + cộng dồn | 4 |
Giá điện tính theo bậc thang: 50 kWh đầu giá 1800 đồng/kWh; từ kWh thứ 51 đến 100 giá 1900; từ kWh thứ 101 đến 200 giá 2200; từ kWh thứ 201 trở đi giá 2500. Cho số điện $n$ ($0 \le n \le 10^9$) một hộ đã dùng, tính số tiền phải trả.
150295000💡 Gợi ý
{0, 50, 100, 200, ∞}, phần nằm trong bậc $k$ là $\max(0, \min(n, \text{mốc}_{k+1}) - \text{mốc}_k)$. Kết quả tới $2{,}5 \cdot 10^{12}$, phải dùng long long.Xem code tham khảo (C++ / Python)
#include <bits/stdc++.h>
using namespace std;
int main(){
long long n;
cin >> n;
long long moc[5] = {0, 50, 100, 200, (long long)4e18};
long long gia[4] = {1800, 1900, 2200, 2500};
long long tien = 0;
for(int k = 0; k < 4; k++){
long long phan = min(n, moc[k + 1]) - moc[k];
if(phan > 0) tien += phan * gia[k];
}
cout << tien;
return 0;
}
n = int(input())
moc = [0, 50, 100, 200, float('inf')]
gia = [1800, 1900, 2200, 2500]
tien = 0
for k in range(4):
phan = min(n, moc[k + 1]) - moc[k]
if phan > 0:
tien += int(phan) * gia[k]
print(tien)
Một số được gọi là số tròn chục chữ số nếu tổng các chữ số của nó chia hết cho 10. Cho $a, b$ ($1 \le a \le b \le 10^6$), đếm các số tròn chục chữ số trong đoạn $[a, b]$.
1 1009💡 Gợi ý
% 10, / 10 (mỗi số tối đa 7 chữ số). Tổng $7 \cdot 10^6$ phép tính, rất nhanh. Viết hàm tongCS(x) cho gọn (bài 5).Xem code tham khảo (C++ / Python)
#include <bits/stdc++.h>
using namespace std;
int tongCS(int x){
int s = 0;
while(x > 0){ s += x % 10; x /= 10; }
return s;
}
int main(){
int a, b;
cin >> a >> b;
int dem = 0;
for(int x = a; x <= b; x++)
if(tongCS(x) % 10 == 0) dem++;
cout << dem;
return 0;
}
a, b = map(int, input().split())
print(sum(1 for x in range(a, b + 1) if sum(map(int, str(x))) % 10 == 0))
Cho một dòng là họ tên được gõ lộn xộn: có thể thừa dấu cách ở đầu, cuối và giữa các từ, chữ hoa chữ thường lẫn lộn (chỉ gồm chữ cái tiếng Anh và dấu cách). Hãy chuẩn hóa: các từ cách nhau đúng một dấu cách, mỗi từ viết hoa chữ cái đầu, các chữ còn lại viết thường.
nGUYEN van aN Nguyen Van An💡 Gợi ý
getline (bài 8). Cách gọn nhất trong C++ là đưa dòng vào stringstream rồi đọc từng từ bằng >>: các dấu cách thừa tự bị bỏ qua. Với mỗi từ, chữ đầu đổi thành hoa bằng toupper, các chữ sau đổi thành thường bằng tolower, rồi nối các từ bằng đúng một dấu cách. Python: " ".join(w.capitalize() for w in s.split()).Xem code tham khảo (C++ / Python)
#include <bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin, s);
stringstream ss(s);
string w, kq = "";
while(ss >> w){
for(int i = 0; i < (int)w.size(); i++)
w[i] = (i == 0) ? toupper(w[i]) : tolower(w[i]);
if(kq != "") kq += " ";
kq += w;
}
cout << kq;
return 0;
}
s = input()
print(" ".join(w.capitalize() for w in s.split()))
Có $n$ đội bóng ($n \le 10^5$), mỗi dòng gồm tên đội (một từ), số bàn thắng, số bàn thua. Xếp hạng theo: hiệu số (thắng − thua) giảm dần; bằng hiệu số thì số bàn thắng giảm dần; vẫn bằng thì tên tăng dần theo thứ tự từ điển. In tên các đội theo thứ tự xếp hạng, mỗi tên một dòng.
4
A 5 2
B 3 0
C 6 3
D 2 2C
A
B
D💡 Gợi ý
ten, thang, thua và hàm cmp 3 tầng như bài 10: so hiệu số trước, rồi số bàn thắng, rồi tên. Nhớ cmp phải dùng >/< nghiêm ngặt. Python: key=lambda d: (-(d[1] - d[2]), -d[1], d[0]).Xem code tham khảo (C++ / Python)
#include <bits/stdc++.h>
using namespace std;
struct Doi { string ten; int thang, thua; };
Doi a[100005];
bool cmp(const Doi &x, const Doi &y){
int hx = x.thang - x.thua, hy = y.thang - y.thua;
if(hx != hy) return hx > hy;
if(x.thang != y.thang) return x.thang > y.thang;
return x.ten < y.ten;
}
int main(){
int n;
cin >> n;
for(int i = 0; i < n; i++) cin >> a[i].ten >> a[i].thang >> a[i].thua;
sort(a, a + n, cmp);
for(int i = 0; i < n; i++) cout << a[i].ten << "\n";
return 0;
}
n = int(input())
a = []
for _ in range(n):
t, w, l = input().split()
a.append((t, int(w), int(l)))
a.sort(key=lambda d: (-(d[1] - d[2]), -d[1], d[0]))
print('\n'.join(d[0] for d in a))
Có nhiệt độ của $n$ ngày liên tiếp ($n \le 10^5$). Một ngày gọi là nắng nóng nếu nhiệt độ từ 35 độ trở lên. Có $q$ câu hỏi ($q \le 10^5$), mỗi câu hỏi gồm $l, r$: từ ngày $l$ đến ngày $r$ có bao nhiêu ngày nắng nóng?
7 3
30 36 35 20 40 34 35
1 3
4 7
1 72
2
4💡 Gợi ý
Xem code tham khảo (C++ / Python)
#include <bits/stdc++.h>
using namespace std;
int S[100005];
int main(){
ios::sync_with_stdio(false); cin.tie(nullptr);
int n, q;
cin >> n >> q;
for(int i = 1; i <= n; i++){
int t; cin >> t;
S[i] = S[i - 1] + (t >= 35 ? 1 : 0);
}
while(q--){
int l, r; cin >> l >> r;
cout << S[r] - S[l - 1] << "\n";
}
return 0;
}
import sys
d = sys.stdin.read().split()
n, q = int(d[0]), int(d[1])
S = [0] * (n + 1)
for i in range(1, n + 1):
S[i] = S[i - 1] + (1 if int(d[1 + i]) >= 35 else 0)
p, out = 2 + n, []
for _ in range(q):
l, r = int(d[p]), int(d[p + 1]); p += 2
out.append(S[r] - S[l - 1])
print('\n'.join(map(str, out)))
Cho $q$ câu hỏi ($q \le 10^5$), mỗi câu hỏi gồm $l, r$ ($1 \le l \le r \le 10^6$): tính tổng các số nguyên tố trong đoạn $[l, r]$.
3
1 10
10 20
2 217
60
2💡 Gợi ý
int (tổng các số nguyên tố dưới $10^6$ khoảng $3{,}7 \cdot 10^{10}$) nên dùng long long.Xem code tham khảo (C++ / Python)
#include <bits/stdc++.h>
using namespace std;
const int N = 1000000;
bool hop[N + 5];
long long P[N + 5];
int main(){
ios::sync_with_stdio(false); cin.tie(nullptr);
hop[0] = hop[1] = true;
for(int i = 2; 1LL * i * i <= N; i++)
if(!hop[i])
for(int j = i * i; j <= N; j += i) hop[j] = true;
for(int i = 1; i <= N; i++) P[i] = P[i - 1] + (hop[i] ? 0 : i);
int q;
cin >> q;
while(q--){
int l, r; cin >> l >> r;
cout << P[r] - P[l - 1] << "\n";
}
return 0;
}
import sys
N = 10**6
nt = bytearray([1]) * (N + 1)
nt[0] = nt[1] = 0
i = 2
while i * i <= N:
if nt[i]:
nt[i * i::i] = bytearray(len(range(i * i, N + 1, i)))
i += 1
P = [0] * (N + 1)
s = 0
for i in range(N + 1):
if nt[i]:
s += i
P[i] = s
d = sys.stdin.read().split()
q = int(d[0])
out = []
for k in range(q):
l, r = int(d[1 + 2 * k]), int(d[2 + 2 * k])
out.append(P[r] - P[l - 1])
print('\n'.join(map(str, out)))
Mô phỏng trực quan – Câu 1. Câu tiền điện bậc thang không khó về thuật toán nhưng rất nhiều bạn mất điểm vì tính nhầm cách "rót" kWh qua các bậc. Bảng giá dưới đây là bảng giá 4 bậc của đề (mốc 0, 50, 100, 200 kWh). Em nhập số kWh (thử cả 30 và 320 như các test mẫu) rồi bấm Tiếp xem từng bậc được lấp đầy ra sao; muốn thử bảng giá khác thì cứ sửa.
Mô phỏng trực quan – Câu 5. Ý tưởng "đánh dấu 0/1 rồi cộng dồn" của câu 5 là cầu nối giữa bài 13 và đề thi. Em theo dõi ba hàng dưới đây: nhiệt độ → mảng đánh dấu → mảng cộng dồn, rồi xem mỗi câu hỏi được trả lời chỉ bằng một phép trừ.
Phần 4Tự tạo test để kiểm tra bài của mình
Khi đi thi, không ai chấm hộ em. Kỹ năng quan trọng của người thi giỏi là tự kiểm tra. Cách chuyên nghiệp gọi là đối chiếu với lời giải “trâu”: viết thêm một chương trình trau.cpp làm theo cách chậm nhưng chắc chắn đúng (thường là duyệt trực tiếp), một chương trình sinh.cpp sinh test ngẫu nhiên nhỏ, rồi cho chạy cả hai và so sánh kết quả hàng trăm lần. Lệch nhau ở test nào thì test đó chính là chỗ bài “xịn” của em bị sai, mà lại là test nhỏ, dễ chạy tay để tìm lỗi.
Ví dụ: sinh test ngẫu nhiên (C++) và chương trình so sánh tự động (Python)
// sinh.cpp: sinh ngẫu nhiên một test nhỏ cho câu 5 (ghi ra màn hình)
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char *argv[]){
srand(atoi(argv[1])); // hạt giống ngẫu nhiên lấy từ tham số dòng lệnh
int n = rand() % 10 + 1, q = rand() % 5 + 1;
cout << n << " " << q << "\n";
for(int i = 1; i <= n; i++) cout << rand() % 21 + 25 << " "; // nhiệt độ 25..45
cout << "\n";
for(int k = 0; k < q; k++){
int l = rand() % n + 1, r = rand() % n + 1;
if(l > r) swap(l, r);
cout << l << " " << r << "\n";
}
return 0;
}
# chay.py: chạy 500 test ngẫu nhiên, so sánh bài chính (bai.exe) với lời giải trâu (trau.exe)
import random, subprocess
for t in range(500):
n, q = random.randint(1, 10), random.randint(1, 5)
a = [random.randint(25, 45) for _ in range(n)]
qs = [sorted((random.randint(1, n), random.randint(1, n))) for _ in range(q)]
test = f"{n} {q}\n{' '.join(map(str, a))}\n" + ''.join(f"{l} {r}\n" for l, r in qs)
kq1 = subprocess.run(["./bai.exe"], input=test, capture_output=True, text=True).stdout.split()
kq2 = subprocess.run(["./trau.exe"], input=test, capture_output=True, text=True).stdout.split()
if kq1 != kq2:
print("SAI o test:\n" + test)
break
else:
print("Ca 500 test deu khop!")
< hay <=, biến chưa khởi tạo, int bị tràn.Phần 5Học tiếp gì sau series nhập môn?
Hoàn thành 14 bài nhập môn là em đã xong “phần móng”. Chặng tiếp theo là học các thuật toán và cấu trúc dữ liệu theo thứ tự từ dễ đến khó: tìm kiếm nhị phân trên kết quả, hai con trỏ, tham lam, đệ quy quay lui, quy hoạch động, đồ thị (BFS, DFS, đường đi ngắn nhất)… Trang Lộ trình học thuật toán từ A đến Z sắp xếp sẵn các chủ đề này kèm hàng trăm bài tập có lời giải chi tiết trên blog. Mỗi ngày giải 1 – 2 bài, đều đặn vài tháng, em sẽ thấy mình tiến bộ rất rõ.
- Không biết học gì trước, học gì sau, học lan man nên kiến thức bị hổng.
- Bí bài không ai gỡ, ngồi cả buổi vẫn không ra rồi bỏ cuộc.
- Code chạy được nhưng không đủ điểm, không biết sai ở đâu, chậm ở đâu.
- Không có đề thi thử và người chấm, nên không biết mình đang ở mức nào.
- Dễ nản giữa chừng khi không có ai theo sát.
- Lộ trình 111 buổi video sắp sẵn từ dòng code đầu tiên đến đề HSG thật của các tỉnh.
- Thầy trực tiếp gỡ bí, chữa bài cho từng em qua nhóm Zalo riêng.
- Hệ thống chấm bài tự động 24/7 và thi thử HSG hằng tuần để biết chính xác mình đang ở đâu.
- Đóng học phí một lần, thầy kèm lâu dài: từ thi chuyên Tin đến HSG quốc gia và cả khi lên đại học.

Nhận xét
Đăng nhận xét