NỘI DUNG
Đề thi HSG Tin học thành phố Yên Bái năm học 2021-2022 (THCS)
Tổng quan về đề thi:
Câu hỏi |
Tên bài |
Tên tệp nộp |
Tên tệp input |
Tên tệp output |
1 |
Hình chữ nhật lớn nhất |
ARECT2.* |
ARECT2.INP |
ARECT2.OUT |
2 |
Đổi tiền |
BXNCHAN.* |
BXNCHAN.INP |
BXNCHAN.OUT |
3 |
Vị trí đẹp |
CLUCKY.* |
CLUCKY.INP |
CLUCKY.OUT |
4 |
Con ong ngoan |
DBEE.* |
DBEE.INP |
DBEE.INP |
Dấu * thay bởi PAS hoặc CPP tương ứng bài làm bằng ngôn ngữ lập trình Pascal hoặc C++
Câu 1: (6.0 điểm) Hình chữ nhật lớn nhất
Cho ba số nguyên dương a, b, c. Hãy chọn 2 trong 3 số này để làm độ dài hai cạnh của một hình chữ nhật có diện tích lớn nhất. Đưa diện tích lớn nhất ra.
Ví dụ: Với a = 12; b = 2; c = 5; Diện tích hình chữ nhật lớn nhất là 60.
Dữ liệu: Vào từ tệp văn bản “ARECT2.INP” ghi ba số nguyên dương a, b, c (Với a, b, c ≤ 109).
Kết quả: Ghi ra tệp văn bản “ARECT2.OUT” số nguyên dương duy nhất là diện tích hình chữ nhật lớn nhất.
ARECT2.INP |
ARECT2.OUT |
12 2 5 |
60 |
Câu 2: (6.0 điểm) Đổi tiền
Jame có số tiền là X (đồng) trong tài khoản ngân hàng. Biết ngân hàng iTeam có các tờ tiền mệnh giá 50, 20 và 10 (đồng). Jame muốn rút X (đồng) ra khỏi tài khoản với số lượng tờ tiền thu được nhỏ hơn hoặc bằng N.
Yêu cầu: Cho X và N. Hãy đếm số lượng cách rút tiền theo yêu cầu của Jame. Ví dụ: Với X = 160; N = 5 → Số cách rút: 2
Với X = 160, N = 2 → Số cách rút: NONE
Dữ liệu: Vào từ tệp văn bản “BXNCHAN.INP” ghi số nguyên dương X và N (X, N ≤ 1000).
Kết quả: Ghi ra tệp văn bản “BXNCHAN.INP” số lượng cách rút tiền theo yêu cầu của Jame. Nếu không có cách rút nào thỏa mãn yêu cầu của Jame thì ghi ra NONE.
BXNCHAN.INP |
BXNCHAN.OUT |
160 5 |
2 |
BXNCHAN.INP |
BXNCHAN.OUT |
160 2 |
NONE |
Câu 3: (4.0 điểm) Vị trí đẹp
Cho N và dãy số nguyên dương a1, a2, …, aN.
Số nguyên tố là số tự nhiên lớn hơn 1 và chỉ có hai ước (là 1 và chính nó). Vị trí i chia dãy số thành hai đoạn con có chỉ số từ [1, i] và từ [i+1,N].
i gọi là vị trí đẹp nếu i chia dãy số thành hai đoạn mà số lượng số nguyên tố trong mỗi đoạn bằng nhau.
Ví dụ: N = 5 và dãy 4, 7, 3, 9, 8. Vị trí đẹp là i = 2.
Dữ liệu: Vào từ tệp văn bản “CLUCKY.INP” gồm:
- Dòng 1: Ghi số nguyên dương N là số lượng phần tử của dãy a (N≤100000).
- Dòng 2: Ghi N số nguyên dương ai (ai ≤ 100000).
Kết quả: Ghi ra tệp văn bản “CLUCKY.INP” gồm một dòng duy nhất ghi các vị trí đẹp tìm được. Mỗi số cách nhau một dấu cách. Nếu không có vị trí đẹp nào thì ghi ra NONE.
CLUCKY.INP |
CLUCKY.INP |
5 4 7 3 9 8 |
2 |
CLUCKY.INP |
CLUCKY.INP |
5 4 6 8 3 12 |
NONE |
Câu 4: (4.0 điểm) Con ong ngoan
Cho xâu S chỉ chứa các kí tự từ „a‟ đến „z‟. Hãy thay thế các xâu “con ong” thành xâu “con ong ngoan” trong xâu S. Các xâu “con ong ngoan” trong xâu ban đầu cần giữ nguyên.
Ví dụ: S = “co mot con ong vang mot con ong ngoan be hon mot con ong to”
Kết quả: “co mot con ong ngoan vang mot con ong ngoan be hon mot con ong ngoan to”
Dữ liệu: Vào từ tệp văn bản “DBEE.INP” ghi xâu S (độ dài xâu bé hơn 255).
Kết quả: Ghi ra tệp văn bản “DBEE.OUT” xâu kết quả.
DBEE.INP |
co mot con ong vang mot con ong ngoan be hon mot con ong to |
DBEE.OUT |
co mot con ong ngoan vang mot con ong ngoan be hon mot con ong ngoan to |
DBEE.INP |
con ong con ong ngoan con ong con ong |
DBEE.OUT |
con ong ngoan con ong ngoan con ong ngoai con ong ngoan |
Tham khảo lời giải đề thi HSG cấp thành phố
Câu 1: (6.0 điểm) Hình chữ nhật lớn nhất
Python
# Đọc dữ liệu từ file
with open('ARECT2.INP', 'r') as f:
a, b, c = map(int, f.readline().split())
# Tính diện tích lớn nhất
max_ab = max(a, b)
max_ac = max(a, c)
max_bc = max(b, c)
max_area = max(max_ab * (c if max_ab == a else b), max_ac * (b if max_ac == a else c), max_bc * (a if max_bc == b else c))
# Ghi kết quả vào file
with open('ARECT2.OUT', 'w') as f:
f.write(str(max_area))
C++
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
int main() {
// Đọc dữ liệu từ file
ifstream infile("ARECT2.INP");
int a, b, c;
infile >> a >> b >> c;
// Tính diện tích lớn nhất
int max_ab = max(a, b);
int max_ac = max(a, c);
int max_bc = max(b, c);
int max_area = max(max_ab * (max_ab == a ? c : b), max(max_ac * (max_ac == a ? b : c), max_bc * (max_bc == b ? c : a)));
// Ghi kết quả vào file
ofstream outfile("ARECT2.OUT");
outfile << max_area;
outfile.close();
return 0;
}
Pascal
program ARECT2;
var
a, b, c, max_ab, max_ac, max_bc, max_area: int64;
infile, outfile: text;
begin
// Đọc dữ liệu từ file
assign(infile, 'ARECT2.INP');
reset(infile);
readln(infile, a, b, c);
close(infile);
// Tính diện tích lớn nhất
max_ab := max(a, b);
max_ac := max(a, c);
max_bc := max(b, c);
max_area := max(max_ab * ifthen(max_ab = a, c, b), max(max_ac * ifthen(max_ac = a, b, c), max_bc * ifthen(max_bc = b, c, a)));
// Ghi kết quả vào file
assign(outfile, 'ARECT2.OUT');
rewrite(outfile);
writeln(outfile, max_area);
close(outfile);
end.
Câu 2: (6.0 điểm) Đổi tiền
Python
# Mở file input và output
with open('BXNCHAN.INP', 'r') as f_input, open('BXNCHAN.OUT', 'w') as f_output:
# Đọc dữ liệu từ file input
x, n = map(int, f_input.readline().strip().split())
# Khởi tạo biến đếm số cách rút tiền
count = 0
# Dùng 3 vòng lặp để tìm số lượng từng loại tiền cần rút
for i in range(x // 50 + 1):
for j in range(x // 20 + 1):
for k in range(x // 10 + 1):
if 50 * i + 20 * j + 10 * k == x and i + j + k <= n:
count += 1
# Ghi kết quả vào file output
if count == 0:
f_output.write("NONE")
else:
f_output.write(str(count))
C++
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream infile("BXNCHAN.INP");
ofstream outfile("BXNCHAN.OUT");
int X, N;
infile >> X >> N;
int count = 0;
for (int i = 0; i <= N; i++) {
for (int j = 0; j <= N; j++) {
for (int k = 0; k <= N; k++) {
int sum = i * 50 + j * 20 + k * 10;
if (sum == X && i + j + k <= N) {
count++;
}
}
}
}
if (count == 0) {
outfile << "NONE";
} else {
outfile << count;
}
infile.close();
outfile.close();
return 0;
}
Pascal
var
X, N, count, i, j, k: integer;
begin
assign(input, 'BXNCHAN.INP');
assign(output, 'BXNCHAN.OUT');
reset(input);
rewrite(output);
readln(X, N);
count := 0;
for i := 0 to X div 50 do
for j := 0 to X div 20 do
for k := 0 to X div 10 do
if (i * 50 + j * 20 + k * 10 = X) and (i + j + k <= N) then
inc(count);
if count > 0 then
writeln(count)
else
writeln('NONE');
close(input);
close(output);
end.
Câu 3: (4.0 điểm) Vị trí đẹp
Python
import math
# Đọc dữ liệu vào từ file input
with open("CLUCKY.INP", "r") as f:
n = int(f.readline().strip())
a = list(map(int, f.readline().strip().split()))
# Tìm số lượng số nguyên tố trong dãy
prime_count = [0] * (n + 1)
for i in range(1, n + 1):
if math.isqrt(a[i - 1]) ** 2 == a[i - 1]: # kiểm tra xem a[i - 1] có phải số chính phương hay không
continue
if all(a[i - 1] % j != 0 for j in range(2, int(math.sqrt(a[i - 1])) + 1)):
prime_count[i] = prime_count[i - 1] + 1
else:
prime_count[i] = prime_count[i - 1]
# Tìm vị trí đẹp
lucky_positions = []
for i in range(1, n + 1):
if 2 * prime_count[i] == i:
lucky_positions.append(i)
# Ghi kết quả ra file output
with open("CLUCKY.OUT", "w") as f:
if len(lucky_positions) == 0:
f.write("NONE")
else:
f.write(" ".join(str(x) for x in lucky_positions))
C++
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
bool isPrime(int n) {
if (n < 2) return false;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return false;
}
return true;
}
int main() {
ifstream in("CLUCKY.INP");
ofstream out("CLUCKY.OUT");
int n;
in >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
in >> a[i];
}
vector<int> prefixSum(n + 1), suffixSum(n + 1);
for (int i = 0; i < n; i++) {
prefixSum[i + 1] = prefixSum[i] + (isPrime(a[i]) ? 1 : 0);
}
for (int i = n - 1; i >= 0; i--) {
suffixSum[i] = suffixSum[i + 1] + (isPrime(a[i]) ? 1 : 0);
}
vector<int> luckyPositions;
for (int i = 1; i < n; i++) {
if (prefixSum[i] == suffixSum[i]) {
luckyPositions.push_back(i + 1);
}
}
if (luckyPositions.empty()) {
out << "NONE";
} else {
for (int pos : luckyPositions) {
out << pos << " ";
}
}
return 0;
}
Pascal
program clucky;
const
MAX_N = 100000;
var
N, i, cnt, sum: longint;
A: array[1..MAX_N] of longint;
isPrime: array[2..MAX_N] of boolean;
res: array[1..MAX_N] of longint;
function isPrimeNumber(n: longint): boolean;
var
i: longint;
begin
if n < 2 then
exit(false);
for i := 2 to trunc(sqrt(n)) do
if n mod i = 0 then
exit(false);
exit(true);
end;
begin
// Đọc dữ liệu vào từ file
assign(input, 'CLUCKY.INP');
reset(input);
readln(N);
for i := 1 to N do
read(A[i]);
close(input);
// Tính số lượng số nguyên tố đến vị trí hiện tại
for i := 2 to N do
begin
if isPrimeNumber(A[i]) then
inc(cnt);
sum := sum + cnt;
if i mod 2 = 0 then
if sum div 2 = (i div 2) then
res[i div 2] := 1;
end;
// Ghi kết quả ra file
assign(output, 'CLUCKY.OUT');
rewrite(output);
cnt := 0;
for i := 1 to N div 2 do
begin
if res[i] = 1 then
begin
write(i * 2, ' ');
inc(cnt);
end;
end;
if cnt = 0 then
writeln('NONE')
else
writeln;
close(output);
end.
Với bài toán trên, nếu sử dụng hàm nguyên tố như trên sẽ không đạt 100% số điểm. Chúng ta nên sử dụng sàng nguyên tố để giải quyết bài toán này.
Python
import math
def sieve(n):
primes = [True] * (n+1)
primes[0] = primes[1] = False
for i in range(2, int(math.sqrt(n))+1):
if primes[i]:
for j in range(i*i, n+1, i):
primes[j] = False
return primes
with open("CLUCKY.INP", "r") as f:
n = int(f.readline())
a = list(map(int, f.readline().split()))
primes = sieve(max(a))
prefix_count = [0] * (n+1)
for i in range(1, n+1):
prefix_count[i] = prefix_count[i-1] + int(primes[a[i-1]])
found = False
with open("CLUCKY.OUT", "w") as f:
for i in range(1, n):
if prefix_count[i] * 2 == prefix_count[n]:
f.write(str(i) + " ")
found = True
if not found:
f.write("NONE")
C++
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
using namespace std;
vector<bool> sieve(int n) {
vector<bool> primes(n+1, true);
primes[0] = primes[1] = false;
for (int i = 2; i <= sqrt(n); i++) {
if (primes[i]) {
for (int j = i*i; j <= n; j += i) {
primes[j] = false;
}
}
}
return primes;
}
int main() {
ifstream in("CLUCKY.INP");
ofstream out("CLUCKY.OUT");
int n;
in >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
in >> a[i];
}
vector<bool> primes = sieve(*max_element(a.begin(), a.end()));
vector<int> prefix_count(n+1, 0);
for (int i = 1; i <= n; i++) {
prefix_count[i] = prefix_count[i-1] + primes[a[i-1]];
}
bool found = false;
for (int i = 1; i < n; i++) {
if (prefix_count[i] * 2 == prefix_count[n]) {
out << i << " ";
found = true;
}
}
if (!found) {
out << "NONE";
}
return 0;
}
Pascal
const
MAXN = 100000;
var
n: longint;
a: array[1..MAXN] of longint;
cnt: array[0..MAXN] of longint;
isPrime: array[1..MAXN] of boolean;
procedure eratosthenes;
var
i, j: longint;
begin
fillchar(isPrime, sizeof(isPrime), true);
isPrime[1] := false;
for i := 2 to n do
if isPrime[i] then
begin
j := 2;
while i * j <= n do
begin
isPrime[i * j] := false;
j := j + 1;
end;
end;
end;
function countPrimes(l, r: longint): longint;
var
i, cnt: longint;
begin
cnt := 0;
for i := l to r do
if isPrime[a[i]] then
cnt := cnt + 1;
exit(cnt);
end;
procedure solve;
var
i, leftCount: longint;
begin
eratosthenes;
cnt[0] := 0;
for i := 1 to n do
cnt[i] := cnt[i - 1] + ord(isPrime[a[i]]);
leftCount := 0;
for i := 1 to n do
begin
if cnt[i] * 2 <> i then
continue;
if cnt[n] - cnt[i] * 2 <> n - i then
continue;
if cnt[i] - cnt[leftCount] = cnt[n] - cnt[i] then
begin
write(i, ' ');
leftCount := i;
end;
end;
if leftCount = 0 then
write('NONE');
end;
begin
readln(n);
for i := 1 to n do
readln(a[i]);
solve;
end.
Câu 4: (4.0 điểm) Con ong ngoan
Python
# Đọc xâu S từ tệp văn bản "DBEE.INP"
with open("DBEE.INP", "r") as f:
S = f.read().strip()
# Thay thế tất cả các xâu "con ong" thành "con ong ngoan"
S = S.replace("con ong", "con ong ngoan")
# Ghi kết quả vào tệp văn bản "DBEE.OUT"
with open("DBEE.OUT", "w") as f:
f.write(S)
C++
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main() {
// Đọc xâu S từ file DBEE.INP
ifstream infile("DBEE.INP");
string S;
getline(infile, S);
// Thay thế tất cả các xâu "con ong" thành "con ong ngoan"
size_t pos = 0;
while ((pos = S.find("con ong", pos)) != string::npos) {
S.replace(pos, 7, "con ong ngoan");
pos += 12; // Dịch vị trí để tránh lặp lại thay thế
}
// Ghi kết quả vào file DBEE.OUT
ofstream outfile("DBEE.OUT");
outfile << S;
outfile.close();
return 0;
}
Pascal
var
f: TextFile;
S: string;
begin
// Đọc xâu S từ file DBEE.INP
Assign(f, 'DBEE.INP');
Reset(f);
ReadLn(f, S);
Close(f);
// Thay thế tất cả các xâu "con ong" thành "con ong ngoan"
S := ReplaceStr(S, 'con ong', 'con ong ngoan');
// Ghi kết quả vào file DBEE.OUT
Assign(f, 'DBEE.OUT');
Rewrite(f);
Write(f, S);
Close(f);
end.