Đề, đáp án thi học sinh giỏi tỉnh Yên Bái năm học 2020-2021

Đề thi học sinh giỏi

Đề 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:

  1. Không chọn đồ vật thứ i: DP[i][j] = DP[i-1][j].

  2. 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.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *