Phần 1. Đề thi
Câu 1. (6,0 điểm) Đếm ký tự in hoa
Cho một xâu ký tự St có độ dài tối đa 255 ký tự, gồm các ký tự được lấy từ tập: ‘a’ … ‘z’; ‘A’ … ‘Z’; ‘0’ … ‘9’ và dấu cách.
Yêu cầu: Hãy đếm số ký tự chữ cái in hoa trong xâu St.
Dữ liệu: Vào từ tệp văn bản CHAR.INP gồm một dòng duy nhất ghi xâu St.
Kết quả: Ghi ra tệp văn bản CHAR.OUT gồm một số nguyên duy nhất là số lượng ký tự chữ cái in hoa đếm được trong xâu St. Nếu không có ký tự in hoa nào thì in ra -1.
Ví dụ:
CHAR.INP | CHAR.OUT |
Ki thi chon HSG lop 9 nam 2022 | 4 |
Câu 2. (6,0 điểm) Tặng quà
Để tri ân cho n khách hàng có số hiệu lần lượt từ 1 đến n, công ty XYZ đã chuẩn bị một chiếc hộp đựng n phiếu quà. Mỗi phiếu quà ghi một số nguyên là giá trị của gói quà mà khách hàng sẽ được nhận. Ban tổ chức cho các khách hàng bốc thăm và ghi nhận lại số trên phiếu quà tương ứng để chuẩn bị cho công tác lên nhận quà.
Yêu cầu: Hãy sắp xếp thứ tự khách hàng lên nhận quà theo giá trị quà từ cao xuống thấp.
Dữ liệu: Vào từ tệp văn bản GIFT.INP gồm:
- Dòng đầu tiên chứa số nguyên n là số lượng khách hàng cần tri ân (0 < n ≤ 10³).
- Dòng thứ hai chứa n số nguyên a₁, a₂, …, aₙ, trong đó aᵢ là số ghi trên phiếu của khách hàng có số hiệu i (1 ≤ i ≤ n; 0 < aᵢ ≤ 10⁹).
Kết quả: Ghi ra tệp văn bản GIFT.OUT một dòng duy nhất gồm n số nguyên tương ứng là số hiệu của n khách hàng theo thứ tự nhận quà từ cao xuống thấp.
- Nếu giá trị quà bằng nhau thì khách hàng có số hiệu nhỏ hơn sẽ được lên nhận quà trước.
- Các số trên một dòng cách nhau bởi khoảng trắng.
Ví dụ:
GIFT.INP | GIFT.OUT |
5 30 11 40 51 51 | 4 5 3 1 2 |
Giải thích:
- Giá trị các món quà từ cao xuống thấp là: 51 51 40 30 11
- Trình tự khách lên nhận quà với số hiệu lần lượt là: 4 5 3 1 2
Câu 3. (5,0 điểm) Ước nguyên tố nhỏ nhất
An là học sinh rất yêu thích môn Toán học nên thường xuyên làm việc với các con số. An vừa học về số nguyên tố và được thầy ra T câu hỏi có dạng như sau:
“Cho trước số nguyên tố X. Hãy cho biết trong đoạn [A..B] có bao nhiêu số nhận X làm ước nguyên tố nhỏ nhất?”.
Yêu cầu: Hãy giúp bạn An trả lời các câu hỏi mà thầy giáo đưa ra.
Dữ liệu: Vào từ tệp văn bản PMIN.INP gồm:
- Dòng đầu tiên ghi số nguyên T là số lượng câu hỏi (1 ≤ T ≤ 100).
- T dòng tiếp theo, mỗi dòng là dữ liệu của một câu hỏi gồm 3 số nguyên: X, A, B
- (2 ≤ X ≤ 10⁵; 1 ≤ A ≤ B ≤ 10⁵).
- Các số trên một dòng cách nhau bởi khoảng trắng.
Kết quả: Ghi ra tệp văn bản PMIN.OUT gồm:
- T dòng, dòng thứ i ghi ra số nguyên tương ứng là kết quả của câu hỏi thứ i.
Ví dụ:
PMIN.INP | PMIN.OUT |
2 2 1 12 5 20 50 | 6 2 |
Giải thích:
- Trong [1..12] có 6 số nhận 2 làm ước nguyên tố nhỏ nhất: 2, 4, 6, 8, 10, 12.
- Trong [20..50] có 2 số nhận 5 làm ước nguyên tố nhỏ nhất: 25, 35.
Câu 4. (3,0 điểm) Mua đồ
Nhân dịp được đi tham quan một khu du lịch nổi tiếng, ghé vào quầy lưu niệm nhỏ, An nhận thấy có n món đồ, món đồ thứ i có giá trị aᵢ (1 ≤ i ≤ n; 0 < aᵢ ≤ 10⁵).
Với dự định là phải tiêu hết số tiền S để mua đồ lưu niệm làm quà tặng cho các bạn ở nhà, An muốn mua được nhiều món đồ nhất có thể. Biết rằng mỗi món đồ là duy nhất.
Yêu cầu: Hãy giúp An thực hiện dự định của mình.
Dữ liệu: Vào từ tệp văn bản BUY.INP gồm:
- Dòng đầu tiên ghi số nguyên n là số món đồ và số nguyên S là số tiền mà An sẽ dùng để mua đồ (2 ≤ n ≤ 25; 0 < S ≤ 10⁶).
- Dòng thứ hai ghi n số nguyên, số nguyên thứ i tương ứng là giá trị của món đồ thứ i.
Kết quả: Ghi ra tệp văn bản BUY.OUT một số nguyên duy nhất là số món đồ nhiều nhất mua được với đúng số tiền S. Nếu không thể mua được thì ghi ra -1.
Lưu ý: Các số trên một dòng cách nhau bởi khoảng trắng.
Ví dụ:
BUY.INP | BUY.OUT |
5 16 4 3 7 15 9 | 3 |
Giải thích: Với số tiền S = 16, mua được nhiều nhất là 3 món đồ (mua món thứ 1, 2 và 5).
Phần 2. Code tham khảo
Câu 1. (6,0 điểm) Đếm ký tự in hoa
#include <iostream>
#include <string>
using namespace std;
int main() {
freopen("CHAR.INP", "r", stdin);
freopen("CHAR.OUT", "w", stdout);
string St;
getline(cin, St); // Đọc toàn bộ dòng từ file
int countUppercase = 0; // Biến đếm số ký tự in hoa
// Duyệt qua từng ký tự trong xâu St
for (char c : St) {
if (c >= 'A' && c <= 'Z') { // Kiểm tra ký tự in hoa
countUppercase++;
}
}
// Ghi kết quả vào file
if (countUppercase > 0) {
cout << countUppercase; // Ghi số lượng ký tự in hoa
} else {
cout << -1; // Không có ký tự in hoa
}
return 0;
}
Câu 2. (6,0 điểm) Tặng quà
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
// Mở file đầu vào và đầu ra
freopen("GIFT.INP", "r", stdin);
freopen("GIFT.OUT", "w", stdout);
int n;
cin >> n; // Đọc số lượng khách hàng
// Vector lưu thông tin {giá trị quà, số hiệu khách hàng}
vector<pair<int, int>> gifts(n);
for (int i = 0; i < n; ++i) {
cin >> gifts[i].first; // Giá trị quà
gifts[i].second = i + 1; // Số hiệu khách hàng (1-based)
}
// Sắp xếp theo yêu cầu:
// 1. Giảm dần theo giá trị quà
// 2. Tăng dần theo số hiệu khách hàng nếu giá trị quà bằng nhau
sort(gifts.begin(), gifts.end(), [](const pair<int, int>& a, const pair<int, int>& b) {
if (a.first != b.first) {
return a.first > b.first; // Sắp xếp giảm dần theo giá trị quà
}
return a.second < b.second; // Sắp xếp tăng dần theo số hiệu khách hàng
});
// Ghi kết quả vào file
for (int i = 0; i < n; ++i) {
cout << gifts[i].second << " "; // In số hiệu khách hàng
}
return 0;
}
Câu 3. (5,0 điểm) Ước nguyên tố nhỏ nhất
#include <iostream>
#include <vector>
using namespace std;
// Hàm sàng Eratosthenes để tìm các số nguyên tố
vector<bool> sieve(int maxLimit) {
vector<bool> isPrime(maxLimit + 1, true);
isPrime[0] = isPrime[1] = false; // 0 và 1 không phải số nguyên tố
for (int i = 2; i * i <= maxLimit; ++i) {
if (isPrime[i]) {
for (int j = i * i; j <= maxLimit; j += i) {
isPrime[j] = false;
}
}
}
return isPrime;
}
int main() {
// Mở file đầu vào và đầu ra
freopen("PMIN.INP", "r", stdin);
freopen("PMIN.OUT", "w", stdout);
int T;
cin >> T; // Số lượng câu hỏi
// Sàng Eratosthenes để tìm các số nguyên tố
const int MAX_LIMIT = 1e5;
vector<bool> isPrime = sieve(MAX_LIMIT);
while (T--) {
int X, A, B;
cin >> X >> A >> B;
// Kiểm tra X có phải số nguyên tố không
if (!isPrime[X]) {
cout << 0 << "\n"; // Nếu X không phải số nguyên tố, kết quả là 0
continue;
}
int count = 0; // Biến đếm số lượng số thỏa mãn
// Duyệt qua các số trong đoạn [A, B]
for (int n = A; n <= B; ++n) {
if (n % X == 0) { // Kiểm tra n có chia hết cho X không
bool isValid = true;
// Kiểm tra không có số nguyên tố nào nhỏ hơn X mà n chia hết
for (int p = 2; p < X; ++p) {
if (isPrime[p] && n % p == 0) {
isValid = false;
break;
}
}
if (isValid) {
count++;
}
}
}
// Ghi kết quả cho câu hỏi hiện tại
cout << count << "\n";
}
return 0;
}
Câu 4. (3,0 điểm) Mua đồ
Cách 1. Sử dụng thuật toán quy hoạch động:
#include <iostream>
#include <vector>
using namespace std;
int main() {
// Mở file đầu vào và đầu ra
freopen("BUY.INP", "r", stdin);
freopen("BUY.OUT", "w", stdout);
int n, S;
cin >> n >> S; // Đọc số món đồ và số tiền
vector<int> prices(n);
for (int i = 0; i < n; ++i) {
cin >> prices[i]; // Đọc giá trị của từng món đồ
}
// Khởi tạo bảng DP
const int INF = -1; // Giá trị khởi tạo cho trường hợp không thể mua
vector<int> dp(S + 1, INF);
dp[0] = 0; // Trường hợp tổng giá trị là 0, số món đồ là 0
// Xây dựng bảng DP
for (int i = 0; i < n; ++i) {
int price = prices[i];
for (int s = S; s >= price; --s) {
if (dp[s - price] != INF && dp[s - price] + 1 > dp[s]) {
dp[s] = dp[s - price] + 1;
}
}
}
// Ghi kết quả vào file
cout << dp[S];
return 0;
}
Cách 2. Sử dụng Thuật toán quay lui
#include <iostream>
#include <vector>
using namespace std;
// Biến toàn cục để lưu kết quả tối ưu
int maxItems = -1;
// Hàm quay lui để tìm số món đồ nhiều nhất
void backtrack(int index, int currentSum, int count, const vector<int>& prices, int S) {
// Nếu tổng hiện tại bằng S, cập nhật kết quả tối ưu
if (currentSum == S) {
maxItems = max(maxItems, count);
return;
}
// Nếu vượt quá S hoặc đã duyệt hết danh sách, dừng lại
if (currentSum > S || index >= prices.size()) {
return;
}
// Thử chọn món đồ hiện tại
backtrack(index + 1, currentSum + prices[index], count + 1, prices, S);
// Thử bỏ qua món đồ hiện tại
backtrack(index + 1, currentSum, count, prices, S);
}
int main() {
// Mở file đầu vào và đầu ra
freopen("BUY.INP", "r", stdin);
freopen("BUY.OUT", "w", stdout);
int n, S;
cin >> n >> S; // Đọc số món đồ và số tiền
vector<int> prices(n);
for (int i = 0; i < n; ++i) {
cin >> prices[i]; // Đọc giá trị của từng món đồ
}
// Gọi hàm quay lui để tìm số món đồ nhiều nhất
backtrack(0, 0, 0, prices, S);
// Ghi kết quả vào file
cout << maxItems;
return 0;
}