NỘI DUNG
Đề thi học sinh giỏi môn Tin học tỉnh Yên Bái năm học 2020-2021 (khối THCS)
TỔNG QUAN ĐỀ THI:
|
Tên bài |
File chương trình |
File dữ liệu vào |
File dữ liệu ra |
Bài 1 |
Lớn nhất và nhỏ nhất |
AGTMM.* |
AGTMM.INP |
AGTMM.OUT |
Bài 2 |
Sắp xếp |
BSORT.* |
BSORT.INP |
BSORT.OUT |
Bài 3 |
Mật mã |
CSPASS.* |
CSPASS.INP |
CSPASS.OUT |
Bài 4 |
Trò chơi |
DSELECT.* |
DSELECT.INP |
DSELECT.OUT |
Dấu * là đại diện cho phần mở rộng, được thay bằng PAS hoặc CPP tùy theo ngôn ngữ lập trình được sử dụng là Pascal hay C++.
Hãy lập trình giải các bài toán sau:
Bài 1. (6,0 điểm) Lớn nhất và nhỏ nhất
Cho các số nguyên dương M, N, P và Q. Hãy tìm giá trị lớn nhất, giá trị nhỏ nhất.
Dữ liệu: Vào từ tệp văn bản AGTMM.INP ghi số nguyên dương M, N, P, Q (M, N, P, Q ≤ 109).
Kết quả: Ghi ra tệp văn bản AGTMM.OUT giá trị lớn nhất và giá trị nhỏ nhất.
Mỗi số cách nhau một dấu cách.
AGTMM.INP |
AGTMM.OUT |
5 2 7 6 |
7 2 |
Bài 2. (6,0 điểm) Sắp xếp
Trong cuộc thi lập trình có N học sinh, học sinh thứ i đạt ai điểm. Ban tổ chức muốn biết:
- Điểm cao nhất và số lượng học sinh đạt điểm cao nhất.
- Điểm cao thứ nhì và số lượng học sinh đạt điểm cao thứ nhì.
Dữ liệu: Vào từ tệp văn bản BSORT.INP gồm:
- Dòng 1: Ghi số nguyên dương N là số lượng học sinh (N ≤ 105).
- Dòng 2: Ghi N số nguyên dương ai là điểm học sinh thứ i (ai ≤ 109).
Kết quả: Ghi ra tệp văn bản BSORT.OUT gồm:
- Dòng 1: Ghi điểm cao nhất và số lượng học sinh đạt điểm cao nhất.
- Dòng 2: Ghi điểm cao thứ nhì và số lượng học sinh đạt điểm cao thứ nhì. Nếu không có điểm cao thứ nhì thì ghi ra NONE.
Mỗi số cách nhau một dấu cách.
BSORT.INP |
BSORT.OUT |
|
BSORT.INP |
BSORT.OUT |
5 7 6 2 7 5 |
7 2 6 1 |
|
5 6 6 6 6 6 |
6 5 NONE |
Bài 3. (5,0 điểm) Mật mã
Công ty CYX có N nhân viên, nhân viên thứ i có mã nhân viên là ai. Để mở cửa thang máy, mỗi nhân viên cần nhập mật mã của mình. Biết rằng mật mã của nhân viên thứ i là dãy các ước nguyên dương của ai.
Ví dụ: Cho N = 3 và dãy các mã nhân viên: 6, 10, 34.
Nhân viên 1: có mật mã là 1236; Vì số 6 có các ước nguyên dương là 1, 2, 3, 6.
Nhân viên 2: có mật mã là 12510; Nhân viên 3: có mật mã là 121734.
Yêu cầu: Hãy xác định mật mã mở cửa thang máy của mỗi nhân viên.
Dữ liệu: Vào từ tệp văn bản CSPASS.INP gồm:
- Dòng 1: Ghi số nguyên dương N là số lượng nhân viên (N ≤ 1000).
- Dòng 2: Ghi N số nguyên dương ai là mã nhân viên thứ i (ai ≤ 108).
Kết quả: Ghi ra tệp văn bản CSPASS.OUT gồm một dòng duy nhất ghi N số nguyên dương là mật mã mở cửa thang máy của mỗi nhân viên.
Mỗi số cách nhau một dấu cách.
CSPASS.INP |
CSPASS.OUT |
3 6 10 34 |
1236 12510 121734 |
Bài 4. (3,0 điểm) Trò chơi
An tham gia trò chơi truyền hình thực tế. Ở trò chơi này Ban tổ chức có N đồ vật, đồ vật thứ i có giá trị ai và khối lượng ci. Người chơi chọn một số đồ vật sao cho tổng khối lượng các đồ vật được chọn thuộc đoạn từ [L, R] và tổng giá trị các đồ vật được chọn là lớn nhất.
Yêu cầu: Hãy xác định tổng giá trị đồ vật lớn nhất mà An có thể nhận được.
Dữ liệu: Vào từ tệp văn bản DSELECT.INP gồm:
- Dòng 1: Ghi số nguyên dương N, L và R (N ≤ 20, L ≤ R ≤ 109).
- Trong N dòng tiếp theo, dòng thứ i ghi số nguyên dương ai và ci (ai, ci ≤ 109).
Dữ liệu vào đảm bảo có ít nhất một cách chọn đồ vật.
Kết quả: Ghi ra tệp văn bản DSELECT.OUT gồm một dòng duy nhất ghi tổng giá trị đồ vật lớn nhất mà An có thể nhận được.
DSELECT.INP |
DSELECT.OUT |
Giải thích |
5 10 17 5 3 2 4 3 6 6 2 8 5 |
22
|
Chọn đồ vật thứ tự 1, 3, 4, 5 có tổng khối lượng là 16 thuộc đoạn [10, 17] và tổng giá trị lớn nhất là 22. |
Đáp án tham khảo
Bài 1. Lớn nhất và nhỏ nhất
Python
with open('AGTMM.INP', 'r') as f:
m, n, p, q = map(int, f.readline().split())
# Tạo danh sách chứa các số
numbers = [m, n, p, q]
# Sắp xếp danh sách
numbers.sort()
# Ghi kết quả ra tệp AGTMM.OUT
with open('AGTMM.OUT', 'w') as f:
f.write(f"{numbers[0]} {numbers[-1]}")
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
ifstream infile("AGTMM.INP");
ofstream outfile("AGTMM.OUT");
int m, n, p, q;
infile >> m >> n >> p >> q;
// Tạo mảng chứa các số
int numbers[] = {m, n, p, q};
// Sắp xếp mảng
sort(numbers, numbers + 4);
// Ghi kết quả ra tệp AGTMM.OUT
outfile << numbers[0] << " " << numbers[3];
return 0;
}
Pascal
var
m, n, p, q, min_num, max_num: longint;
infile, outfile: text;
numbers: array[1..4] of longint;
begin
assign(infile, 'AGTMM.INP');
reset(infile);
readln(infile, m, n, p, q);
close(infile);
// Lưu các số vào mảng
numbers[1] := m;
numbers[2] := n;
numbers[3] := p;
numbers[4] := q;
// Sắp xếp mảng
for var i := 1 to 3 do
for var j := i + 1 to 4 do
if numbers[i] > numbers[j] then
begin
var temp := numbers[i];
numbers[i] := numbers[j];
numbers[j] := temp;
end;
min_num := numbers[1];
max_num := numbers[4];
// Ghi kết quả ra tệp AGTMM.OUT
assign(outfile, 'AGTMM.OUT');
rewrite(outfile);
writeln(outfile, min_num, ' ', max_num);
close(outfile);
end.
Bài 2. Sắp xếp
Python
# Đọc dữ liệu từ file vào mảng
with open('BSORT.INP') as f:
n = int(f.readline().strip())
scores = list(map(int, f.readline().strip().split()))
# Sắp xếp mảng giảm dần
scores.sort(reverse=True)
# Tìm điểm cao nhất và số lượng học sinh đạt điểm cao nhất
max_score = scores[0]
num_max = scores.count(max_score)
# Tìm điểm cao thứ nhì và số lượng học sinh đạt điểm cao thứ nhì (nếu có)
second_max_score = None
num_second_max = 0
for score in scores:
if score < max_score:
second_max_score = score
num_second_max = scores.count(score)
break
# Ghi kết quả ra file
with open('BSORT.OUT', 'w') as f:
f.write(f'{max_score} {num_max}\n')
if second_max_score is not None:
f.write(f'{second_max_score} {num_second_max}\n')
else:
f.write('NONE\n')
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
ifstream infile("BSORT.INP");
ofstream outfile("BSORT.OUT");
int n;
infile >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
infile >> a[i];
}
// Tìm điểm cao nhất và số lượng học sinh đạt điểm cao nhất
int max_score = *max_element(a.begin(), a.end());
int count_max_score = count(a.begin(), a.end(), max_score);
outfile << max_score << " " << count_max_score << endl;
// Tìm điểm cao thứ nhì và số lượng học sinh đạt điểm cao thứ nhì
int second_max_score = -1;
int count_second_max_score = 0;
for (int i = 0; i < n; i++) {
if (a[i] != max_score && a[i] > second_max_score) {
second_max_score = a[i];
count_second_max_score = 1;
} else if (a[i] == second_max_score) {
count_second_max_score++;
}
}
if (count_second_max_score == 0) {
outfile << "NONE";
} else {
outfile << second_max_score << " " << count_second_max_score;
}
infile.close();
outfile.close();
return 0;
}
Pascal
#include <bits/stdc++.h>
using namespace std;
int main() {
ifstream infile("BSORT.INP");
ofstream outfile("BSORT.OUT");
int n;
infile >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
infile >> a[i];
}
// Tìm điểm cao nhất và số lượng học sinh đạt điểm cao nhất
int max_score = *max_element(a.begin(), a.end());
int count_max_score = count(a.begin(), a.end(), max_score);
outfile << max_score << " " << count_max_score << endl;
// Tìm điểm cao thứ nhì và số lượng học sinh đạt điểm cao thứ nhì
int second_max_score = -1;
int count_second_max_score = 0;
for (int i = 0; i < n; i++) {
if (a[i] != max_score && a[i] > second_max_score) {
second_max_score = a[i];
count_second_max_score = 1;
} else if (a[i] == second_max_score) {
count_second_max_score++;
}
}
if (count_second_max_score == 0) {
outfile << "NONE";
} else {
outfile << second_max_score << " " << count_second_max_score;
}
infile.close();
outfile.close();
return 0;
}
Bài 3. Mật mã
Python
import math
def get_password(x):
password = str(x)
for i in range(1, int(math.sqrt(x))+1):
if x % i == 0:
password += str(i)
if i != x // i:
password += str(x // i)
return password
# Đọc dữ liệu vào
with open('CSPASS.INP', 'r') as f:
n = int(f.readline())
a = list(map(int, f.readline().split()))
# Tính mật mã cho từng nhân viên và ghi kết quả vào file
with open('CSPASS.OUT', 'w') as f:
for i in range(n):
password = get_password(a[i])
f.write(password + ' ')
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
// Mở file input và output
freopen("CSPASS.INP", "r", stdin);
freopen("CSPASS.OUT", "w", stdout);
int n;
cin >> n;
// Đọc dãy mã nhân viên và tìm các ước của mỗi mã
vector<vector<int>> divisors(n);
for (int i = 0; i < n; i++) {
int a;
cin >> a;
for (int d = 1; d * d <= a; d++) {
if (a % d == 0) {
divisors[i].push_back(d);
if (d != a / d) {
divisors[i].push_back(a / d);
}
}
}
sort(divisors[i].begin(), divisors[i].end());
}
// Tạo mật mã cho mỗi nhân viên
for (int i = 0; i < n; i++) {
int passcode = 0;
for (int d : divisors[i]) {
passcode = passcode * 10 + d;
}
cout << passcode << " ";
}
return 0;
}
Pascal
program CSPASS;
var
n, i, j: longint;
a: array[1..1000] of longint;
begin
// Mở file input để đọc dữ liệu
assign(input, 'CSPASS.INP');
reset(input);
// Đọc dữ liệu
readln(n);
for i := 1 to n do
readln(a[i]);
// Đóng file input
close(input);
// Mở file output để ghi kết quả
assign(output, 'CSPASS.OUT');
rewrite(output);
// Tính mật mã cho từng nhân viên và ghi kết quả
for i := 1 to n do begin
write(a[i]);
for j := 1 to a[i] do
if a[i] mod j = 0 then
write(j);
writeln;
end;
// Đóng file output
close(output);
end.
Bài 4. Trò chơi
Để giải bài toán này, ta có thể sử dụng thuật toán Quy hoạch động (Dynamic Programming) để tính tổng giá trị lớn nhất mà An có thể nhận được trong khoảng từ [1, i], i = 1, 2, …, N, rồi lấy kết quả ở vị trí R trên bảng DP.
Cụ thể, ta tạo bảng DP có kích thước (N+1) x (R+1), với DP[i][j] là tổng giá trị lớn nhất mà An có thể nhận được trong khoảng từ [1, i] với tổng khối lượng không vượt quá j.
Để tính DP[i][j], ta có hai trường hợp:
-
Không chọn đồ vật thứ i: DP[i][j] = DP[i-1][j].
-
Chọn đồ vật thứ i: DP[i][j] = DP[i-1][j-ci] + ai.
Sau khi tính toán xong bảng DP, kết quả của bài toán là giá trị lớn nhất trong dãy DP[N][L], DP[N][L+1], …, DP[N][R].
Python
# Đọc dữ liệu từ file input
with open('DSELECT.INP', 'r') as f:
n, l, r = map(int, f.readline().split())
a = []
c = []
for i in range(n):
ai, ci = map(int, f.readline().split())
a.append(ai)
c.append(ci)
# Tính tổng giá trị lớn nhất của đồ vật được chọn
ans = 0
for i in range(l-1, r):
for j in range(i, r):
cur_weight = sum(c[i:j+1])
if cur_weight <= r-l+1:
cur_value = sum(a[i:j+1])
if cur_value > ans:
ans = cur_value
# Ghi kết quả vào file output
with open('DSELECT.OUT', 'w') as f:
f.write(str(ans))
C++
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
// Khai báo cấu trúc đồ vật
struct Item {
int value, weight;
// Constructor
Item(int v, int w) : value(v), weight(w) {}
};
// Hàm đọc dữ liệu từ file
void readData(vector<Item>& items, int& n, int& l, int& r) {
ifstream inFile("DSELECT.INP");
if (inFile.is_open()) {
inFile >> n >> l >> r;
for (int i = 0; i < n; i++) {
int value, weight;
inFile >> value >> weight;
items.push_back(Item(value, weight));
}
inFile.close();
}
}
// Hàm ghi kết quả vào file
void writeData(int result) {
ofstream outFile("DSELECT.OUT");
if (outFile.is_open()) {
outFile << result;
outFile.close();
}
}
// Hàm tìm giá trị lớn nhất của một tập đồ vật có tổng trọng lượng nằm trong khoảng [l, r]
int knapsack(vector<Item>& items, int n, int l, int r) {
int dp[r - l + 1] = {0}; // Khởi tạo mảng dp với giá trị mặc định là 0
for (int i = 0; i < n; i++) {
for (int j = r - items[i].weight; j >= l - items[i].weight; j--) {
// Cập nhật giá trị lớn nhất của các tập đồ vật có tổng trọng lượng nằm trong khoảng [j + items[i].weight, j]
if (j + items[i].weight <= r && j + items[i].weight >= l) {
dp[j - l + items[i].weight] = max(dp[j - l + items[i].weight], dp[j - l] + items[i].value);
}
}
}
return dp[r - l];
}
int main() {
int n, l, r;
vector<Item> items;
readData(items, n, l, r); // Đọc dữ liệu từ file
int result = knapsack(items, n, l, r); // Tìm giá trị lớn nhất
writeData(result); // Ghi kết quả vào file
return 0;
}
Pascal
const MAXN = 20;
var
N, L, R, i, j, k: longint;
a, c, dp: array[1..MAXN] of int64;
f: text;
function max(a, b: int64): int64;
begin
if a > b then max := a
else max := b;
end;
begin
// Đọc dữ liệu vào từ file
assign(f, 'DSELECT.INP');
reset(f);
readln(f, N, L, R);
for i := 1 to N do
readln(f, a[i], c[i]);
close(f);
// Tính toán các giá trị trong mảng dp
fillchar(dp, sizeof(dp), 0);
for i := 1 to N do
begin
for j := i downto 1 do
begin
for k := j to i do
begin
if (c[k] >= L) and (c[k] <= i) then
dp[i] := max(dp[i], dp[j-1] + a[k]);
end;
end;
end;
// Tìm giá trị lớn nhất trong mảng dp
// và ghi kết quả ra file
assign(f, 'DSELECT.OUT');
rewrite(f);
writeln(f, dp[N]);
close(f);
end.