Đề, đáp án thi học sinh giỏi thành phố Yên Bái năm học 2020 – 2021

Đề thi học sinh giỏi

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

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 *