Đề, Đáp án thi Tin học trẻ thành phố Yên Bái năm 2023

Đề thi Tin học trẻ

Phần 1. Đề thi

Câu 1. Khóa số (6 điểm)

          Trong một chuyến khảo cổ trong khu rừng nguyên sinh, các nhà khảo cổ học đã phát hiện ra một kho báu bí mật được xây dựng rất kiên cố và không thể phá bỏ. Họ cho rằng trong đó có thể là những khối tài sản rất có giá trị và họ tìm cách mở cánh cửa của những kho báu đó.

          Trên cửa mỗi kho báu có một bảng gồm 2 hàng, hàng 1 ghi sẵn số nguyên dương N (n <= 10^6), hàng 2 chứa 2 khóa số K1 và K2 như hình dưới đây:

N

K1

K2

          Trong khi khảo sát, các nhà khảo cổ đã phát hiện một phiến đá có ghi cách để mở khóa như sau:

          Để mở được khóa cửa kho báu ta cần phải thực hiện 2 thao tác:

          – Điều chỉnh khóa số K1 về số là số lượng ước nguyên tố của N

          – Điều chỉnh khóa số K2 về số là tổng các ước nguyên tố của N

          Sau khi điều chỉnh 2 khóa K1 và K2 như trên thì cánh cửa sẽ tự động mở ra và nhà khảo cổ có thể vào bên trong một cách dễ dàng.

          Ví dụ: Ở kho báu trên cửa ghi số N = 12, có các ước của N là 1, 2, 3, 4, 6, 12 chỉ có 2 ước nguyên tố là 2 và 3 nên K1 = 2 và K2 = 5. Như vậy ta cần điều chỉnh khóa K1 về số 2 và khóa K2 về số 5 thì sẽ mở được cửa kho báu.

Em hãy lập trình tìm khóa mở cửa kho báu giúp các nhà khảo cổ nhé.

Dữ liệu: Vào từ tệp văn bản PASS.INP gồm 1 dòng duy nhất chứa số nguyên dương N (N <= 10^6)

Kết quả: Ghi ra tệp PASS.OUT hai số nguyên K1 và K2.

Ví dụ:

PASS.INP

PASS.OUT

Giải thích

12

2 5

Số 12 có 2 ước nguyên tố là 2 và 3 nên K1 = 2, tổng của 2 ước nguyên tố này là 5 nên K2 = 5.

 

Câu 2. Đoạn con (6 điểm)

          Masha là một cô bé thông minh và tinh nghịch sống cùng một chú gấu trong bộ phim hoạt hình nổi tiếng “Masha và chú gấu xiếc”. Masha rất thích ăn kẹo, gấu vốn yêu chiều Masha nên trong nhà gấu luôn có sẵn các hộp kẹo đầy màu sắc. Nhưng do ăn quá nhiều kẹo nên Masha đã bị sâu răng. Vì thế gấu quyết định cất tất cả các hộp kẹo vào một chiếc tủ đặc biệt và khóa lại cẩn thận. Gấu có n hộp kẹo đánh số từ 1 đến n, trong hộp thứ i có ai chiếc kẹo. Những hộp kẹo này được xếp vào tủ theo hàng ngang lần lượt từ hộp thứ 1 đến hộp thứ n. Cuối học kỳ vừa rồi Masha đạt kết quả tốt nên gấu quyết định sẽ thưởng cho Masha một số hộp kẹo. Nhưng chiếc tủ cất kẹo của gấu được thiết kế đặc biệt nên gấu chỉ có thể lấy các hộp kẹo ra theo 3 quy tắc sau:

          – Phải lấy ra hộp chứa chứa ít kẹo nhất và hộp chứa nhiều kẹo nhất trong số n số hộp kẹo ban đầu.

          – Các hộp kẹo lấy ra phải liên tiếp nhau.

          – Số lượng hộp kẹo lấy ra là ít nhất.

Yêu cầu: Hãy tìm số lượng hộp kẹo mà gấu lấy ra thưởng cho Masha theo quy tắc trên.

Dữ liệu: Vào từ tệp văn bản DOANCON.INP gồm:

          – Dòng đầu chưa số nguyên dương n là số lượng hộp kẹo (n <= 10^5)

          – Dòng tiếp theo chứa n số nguyên a1, a2,… an là số lượng họp kẹo trong mỗi hộp (|ai| <= 10^9)

          – Các số trên một dòng cách nhau bởi dấu cách.

Kết quả: Ghi ra tệp văn bản DOANCON.OUT một số là số lượng hộp kẹo mà gấu thưởng cho Masha.

Ví dụ:

DOANCON.INP

DOANCON.OUT

Giải thích

5

2 1 5 20 25

4

Gấu thưởng cho Masha 4 hộp kẹo ở vị trí 2, 3, 4, 5

10

1 3 6 2 8 2 1 3 5 8

3

Gấu thưởng cho Masha 3 hộp kẹo ở vị trí 5, 6, 7

 

Câu 3. Mật khẩu (4 điểm)

          Đánh giá độ mạnh của mật khẩu là một bài toán quan trọng của ngành An Toàn Thông Tin. Trong bài tập này, nhiệm vụ của bạn là đánh giá độ an toàn của một mật khẩu bằng trọng số được gán cho các ký tự:

          – Các mật khẩu chỉ bao gồm ký tự tiếng Anh viết thường.

          – Mỗi chữ cái tiếng Anh viết thường được gán một số nguyên từ 0 đến 25 theo cách như sau: Trọng số của ký tự ‘a’ được cho biết trước. Trọng số các ký tự còn lại được gán theo thứ tự vòng tròn. Ví dụ, nếu trọng số của ‘a’ là 5, trọng số của ‘b’ sẽ là 6, trọng số của ‘c’ là 7,… trọng số củ ‘u’ là 25, trọng số của ‘v’ là 0…. Trọng số của ‘z’ là 4.

          – Độ mạnh của một chuỗi mật khẩu là trọng số của các ký tự trong nó.

Yêu cầu: Cho trước một xâu ký tự thể hiện mật khẩu và trọng số của ký tự là ‘a’. Hãy tính độ mạnh của mật khẩu đó.

Dữ liệu: Lấy từ MK.INP

          – Dòng 1 chứa mật khẩu là một xâu gồm từ 1 tới 100 chữ cái tiếng Anh in thường.

          – Dòng 2 chứa một số nguyên x duy nhất là trọng số của ký tự ‘a’ (0<=x<=25)

Kết quả: Ghi ra tệp MK.OUT gồm 1 số nguyên duy nhất là độ mạnh của mật khẩu.

Ví dụ:

MK.INP

MK.OUT

abc

1

6

 

Câu 4. Phần thưởng (4 điểm)

          Phú ông có N đồ vật đánh số từ 1 đến N, vật thứ I có giá trị là số nguyên ai. Bờm là người luôn đem lại vui vẻ cho Phú Ông mỗi khi ông buồn nên được Phú Ông ban phần thưởng bằng tổng giá trị các vật liên tiếp từ số hiệu i đến j (1 <=j, i,j = 1…N). Phú Ông nổi tiếng keo kiệt, đồ vật được cất kỹ trong kho từ rất lâu, nên có vật rất giá trị (ai >= 0) nhưng cũng có những vật quá hạn sử dụng, hỏng hóc, cũ kỹ,… cho không cũng không ai thèm (ai < 0). Như vậy, Bờm có thể nhận được phần thưởng có giá trị âm. Do bị quá nhiều người kêu ca về tính keo kiệt nên Phú Ông đã thay đổi sang cách tính phần thưởng mới bằng trị tuyệt đối của tổng giá trị các vật mà Bờm được chọn từ vật thứ i đến vật thứ j lớn hơn giá trị S cho trước.

Yêu cầu: Bạn hãy xác định giúp Bờm số lượng cách lựa chọn phần thưởng thỏa mãn điều kiện của Phú Ông đưa ra.

Dữ liệu: vào từ file văn bản ASUM.INP có cấu trúc:

          – Dòng 1 chứa 2 số nguyên N và S (N <= 10^5; S <= 10^5)

          – Dòng 2 chứa N số nguyên ai với i = 1, 2, … N

Kết quả: đưa ra file văn bản ASUM.OUT một số duy nhất C tìm được theo yêu cầu của bài toán.

Ví dụ:

ASUM.INP

ASUM.OUT

4 4

5 -1 8 -5

6

 

Phần 2. Đáp án tham khảo

Câu 1. Khóa số (6 điểm)

Python

import math

# Đọc dữ liệu từ tệp PASS.INP
with open('PASS.INP', 'r') as f:
    n = int(f.readline().strip())

# Tìm ước số nguyên tố và tổng ước của N
prime_factors = set()
sum_factors = 1 # chứa ước số 1
for i in range(2, int(math.sqrt(n))+1):
    if n % i == 0:
        prime_factors.add(i)
        prime_factors.add(n//i)
        sum_factors += i + n//i
if math.sqrt(n) % 1 == 0: # n là số chính phương
    prime_factors.add(int(math.sqrt(n)))
    sum_factors += int(math.sqrt(n))

# Điều chỉnh khóa số K1 và K2
k1 = len(prime_factors)
k2 = sum_factors

# Ghi kết quả ra tệp PASS.OUT
with open('PASS.OUT', 'w') as f:
    f.write(f"{k1} {k2}")

C++

#include <bits/stdc++.h>
using namespace std;

int main() {
    freopen("PASS.INP", "r", stdin);
    freopen("PASS.OUT", "w", stdout);

    int n;
    cin >> n;

    // Tìm ước số nguyên tố và tổng ước của N
    set<int> prime_factors;
    int sum_factors = 1; // chứa ước số 1
    for (int i = 2; i <= sqrt(n); i++) {
        if (n % i == 0) {
            prime_factors.insert(i);
            prime_factors.insert(n/i);
            sum_factors += i + n/i;
        }
    }
    if (sqrt(n) == floor(sqrt(n))) { // n là số chính phương
        prime_factors.insert(sqrt(n));
        sum_factors += sqrt(n);
    }

    // Điều chỉnh khóa số K1 và K2
    int k1 = prime_factors.size();
    int k2 = sum_factors;

    // Ghi kết quả ra tệp PASS.OUT
    cout << k1 << " " << k2;

    return 0;
}

Pascal

program unlockTreasure;
var
  n, i, K1, K2, sum: longint;
  f: text;
begin
  assign(f, 'PASS.INP');
  reset(f);
  readln(f, n);
  close(f);
  
  K1 := 0;
  for i := 1 to n do
    if n mod i = 0 then
      if (i = 1) or (i = n) then
        inc(K1);
  
  K2 := 0;
  for i := 1 to n do
    if n mod i = 0 then
      inc(K2, i);
  
  assign(f, 'PASS.OUT');
  rewrite(f);
  writeln(f, K1);
  writeln(f, K2);
  close(f);
end.

Câu 2. Đoạn con (6 điểm)

Để giải quyết bài toán này, ta có thể sử dụng thuật toán quy hoạch động. Ta sẽ tính toán tất cả các phạm vi liên tiếp của các hộp kẹo và tìm ra phạm vi có số lượng kẹo lớn nhất, từ đó xác định được số lượng hộp kẹo cần lấy ra.

Đầu tiên, ta đọc dữ liệu từ file DOANCON.INP và lưu trữ số lượng kẹo trong mỗi hộp vào một mảng a.

Sau đó, ta tính toán các phạm vi liên tiếp của mảng a bằng cách duyệt từ đầu đến cuối mảng và tính toán tổng các phần tử trong phạm vi hiện tại. Nếu tổng này lớn hơn tổng lớn nhất đã tìm thấy trước đó, ta cập nhật lại phạm vi có tổng lớn nhất và lưu trữ chỉ số bắt đầu và kết thúc của phạm vi đó.

Cuối cùng, ta ghi số lượng hộp kẹo cần lấy ra vào file DOANCON.OUT.

Python

# Đọc dữ liệu từ file
with open("DOANCON.INP", "r") as f:
    n = int(f.readline())
    a = list(map(int, f.readline().split()))

# Tính toán phạm vi liên tiếp có tổng lớn nhất
start, end = 0, 0
max_sum = a[0]
cur_sum = a[0]
for i in range(1, n):
    if cur_sum < 0:
        cur_sum = 0
        start = i
    cur_sum += a[i]
    if cur_sum > max_sum:
        max_sum = cur_sum
        end = i

# Ghi kết quả vào file
with open("DOANCON.OUT", "w") as f:
    f.write(str(end - start + 1))

C++

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1e5 + 5;

int n, a[MAXN];
int dp1[MAXN], dp2[MAXN];

int main() {
    freopen("DOANCON.INP", "r", stdin);
    freopen("DOANCON.OUT", "w", stdout);

    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }

    // tính dp1
    dp1[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (a[i] >= a[i - 1]) {
            dp1[i] = dp1[i - 1] + 1;
        } else {
            dp1[i] = 1;
        }
    }

    // tính dp2
    dp2[n] = 1;
    for (int i = n - 1; i >= 1; i--) {
        if (a[i] <= a[i + 1]) {
            dp2[i] = dp2[i + 1] + 1;
        } else {
            dp2[i] = 1;
        }
    }

    // tìm kết quả
    int res = 1;
    for (int i = 2; i <= n; i++) {
        if (a[i] > a[i - 2]) {
            res = max(res, dp1[i - 1] + dp2[i]);
        }
    }

    cout << res << endl;

    return 0;
}

Pascal

program doancon;
const
  MAXN = 100000;
var
  n, res, l, r: longint;
  a: array[1..MAXN] of longint;
  fmax, fmin, max1, max2, min1, min2: array[0..MAXN] of longint;
  fin, fout: text;
  
procedure readInput;
var
  i: longint;
begin
  assign(fin, 'DOANCON.INP');
  reset(fin);
  readln(fin, n);
  for i := 1 to n do
    read(fin, a[i]);
  close(fin);
end;

procedure writeOutput(res: longint);
begin
  assign(fout, 'DOANCON.OUT');
  rewrite(fout);
  write(fout, res);
  close(fout);
end;

procedure DP;
var
  i: longint;
begin
  fmax[0] := 0;
  fmin[0] := 0;
  max1[0] := 0;
  max2[n+1] := 0;
  min1[0] := 0;
  min2[n+1] := 0;
  for i := 1 to n do
  begin
    max1[i] := max(max1[i-1] + a[i], 0);
    max2[n-i+1] := max(max2[n-i+2] + a[n-i+1], 0);
    min1[i] := min(min1[i-1] + a[i], 0);
    min2[n-i+1] := min(min2[n-i+2] + a[n-i+1], 0);
    fmax[i] := max(max(fmax[i-1], max1[i]), max2[i]);
    fmin[i] := min(min(fmin[i-1], min1[i]), min2[i]);
  end;
  res := n;
  l := 1;
  r := 1;
  while (r <= n) do
  begin
    while (r <= n) and (fmax[r] - fmin[r] <= 1) do 
      Inc(r);
    res := min(res, r - l);
    Inc(l);
  end;
end;

begin
  readInput;
  DP;
  writeOutput(res);
end.

Câu 3. Mật khẩu (4 điểm)

Python

# Đọc dữ liệu vào từ file MK.INP
with open('MK.INP', 'r') as f:
    password = f.readline().strip()
    weight_of_a = int(f.readline())

# Tính trọng số của các ký tự và lưu vào mảng tĩnh weights
weights = [(weight_of_a + i) % 26 for i in range(26)]

# Tính tổng trọng số của mật khẩu
strength = sum(weights[ord(c) - ord('a')] for c in password)

# Ghi kết quả ra file MK.OUT
with open('MK.OUT', 'w') as f:
    f.write(str(strength))

C++

#include <bits/stdc++.h>
using namespace std;

int main() {
    // Mở file input và output bằng hàm freopen
    freopen("MK.INP", "r", stdin);
    freopen("MK.OUT", "w", stdout);

    string password;
    int weight_of_a;

    // Đọc dữ liệu vào
    cin >> password >> weight_of_a;

    // Tính trọng số của các ký tự và lưu vào mảng tĩnh weights
    vector<int> weights(26);
    for (int i = 0; i < 26; i++) {
        weights[i] = (weight_of_a + i) % 26;
    }

    // Tính độ mạnh của mật khẩu
    int strength = 0;
    for (char c : password) {
        strength += weights[c - 'a'];
    }

    // Ghi kết quả ra file MK.OUT
    cout << strength << endl;

    return 0;
}

Pascal

var
  f: text;
  password: string;
  weight_of_a, i, strength: integer;
  weights: array[0..25] of integer;

begin
  // Mở file input và output
  assign(f, 'MK.INP');
  reset(f);
  assign(output, 'MK.OUT');
  rewrite(output);
  reset(output);

  // Đọc dữ liệu vào
  readln(f, password);
  readln(f, weight_of_a);

  // Tính trọng số của các ký tự và lưu vào mảng tĩnh weights
  for i := 0 to 25 do begin
    weights[i] := (weight_of_a + i) mod 26;
  end;

  // Tính độ mạnh của mật khẩu
  strength := 0;
  for i := 1 to length(password) do begin
    strength := strength + weights[ord(password[i]) - ord('a')];
  end;

  // Ghi kết quả ra file MK.OUT
  writeln(strength);

  // Đóng file input và output
  close(f);
  close(output);
end.

Câu 4. Phần thưởng (4 điểm)

Để giải quyết bài toán này, ta có thể sử dụng thuật toán quy hoạch động để tính toán số cách lựa chọn phần thưởng thỏa mãn yêu cầu của Phú Ông.

Ý tưởng:

  • Đầu tiên, ta tính toán giá trị tuyệt đối của mảng ai để xử lý cho bài toán này.
  • Sau đó, ta sử dụng một mảng dp để tính toán số cách lựa chọn phần thưởng thỏa mãn yêu cầu của Phú Ông.
  • Mảng dp này có kích thước là N+1, mỗi phần tử dp[i] sẽ chứa số cách lựa chọn phần thưởng thỏa mãn yêu cầu của Phú Ông từ vật đầu tiên đến vật thứ i.
  • Để tính toán giá trị dp[i], ta sử dụng hai biến l và r để lưu vị trí các vật liên tiếp từ vật đầu tiên đến vật i có tổng giá trị lớn hơn hoặc bằng S. Sau đó, giá trị dp[i] sẽ được tính bằng dp[i-1] cộng thêm số cách lựa chọn phần thưởng từ các vật liên tiếp từ vật l+1 đến vật i có tổng giá trị lớn hơn hoặc bằng S, trừ đi số cách lựa chọn phần thưởng từ các vật liên tiếp từ vật r+1 đến vật i có tổng giá trị lớn hơn hoặc bằng S.

Python

def reward(n, s, a):
    # Khởi tạo mảng dp có kích thước (n+1)x(n+1) và giá trị ban đầu đều là 0
    dp = [[0 for j in range(n+1)] for i in range(n+1)]
    
    # Khởi tạo biến count để đếm số lượng cách lựa chọn phần thưởng thỏa mãn yêu cầu
    count = 0
    
    # Duyệt tất cả các cặp (i, j) với 1 <= i <= j <= n
    for i in range(1, n+1):
        for j in range(i, n+1):
            # Cập nhật giá trị của dp[i][j] bằng tổng giá trị các vật liên tiếp từ số hiệu i đến j
            dp[i][j] = dp[i][j-1] + a[j]
            
            # Nếu tổng giá trị các vật từ i đến j lớn hơn giá trị S
            if abs(dp[i][j]) > s:
                # Tăng biến count lên 1
                count += 1
                
                # Duyệt tất cả các cặp (x, y) với i <= x <= y <= j
                for x in range(i, j+1):
                    for y in range(x, j+1):
                        # Nếu tổng giá trị các vật từ x đến y lớn hơn giá trị S
                        if abs(dp[x][y]) > s:
                            # Giảm biến count đi 1
                            count -= 1
    
    # Trả về số lượng cách lựa chọn phần thưởng thỏa mãn yêu cầu
    return count


# Hàm đọc dữ liệu từ file và trả về giá trị tương ứng của N, S và mảng a
def read_input(file_path):
    with open(file_path, 'r') as f:
        n, s = map(int, f.readline().split())
        a = list(map(int, f.readline().split()))
        return n, s, a


# Hàm ghi kết quả vào file
def write_output(file_path, result):
    with open(file_path, 'w') as f:
        f.write(str(result))


# Đọc dữ liệu từ file input.txt
n, s, a = read_input('ASUM.INP')

# Tính số lượng cách lựa chọn phần thưởng thỏa mãn yêu cầu
count = reward(n, s, a)

# Ghi kết quả vào file output.txt
write_output('ASUM.OUT', count)

C++

#include <bits/stdc++.h>
using namespace std;

int main() {
    // Mở file input và output
    freopen("ASUM.INP", "r", stdin);
    freopen("ASUM.OUT", "w", stdout);

    // Đọc dữ liệu
    int n, s;
    cin >> n >> s;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }

    // Tính số lượng cách lựa chọn phần thưởng thỏa mãn điều kiện
    int ans = 0;
    vector<int> f(n + 1);
    f[1] = abs(a[1]);
    if (f[1] >= abs(s)) {
        ans++;
    }
    for (int i = 2; i <= n; i++) {
        f[i] = abs(a[i]);
        for (int j = i - 1; j >= 1; j--) {
            f[j] += abs(a[i]);
            if (f[j] >= abs(s)) {
                ans += i - j;
            }
        }
        if (f[i] >= abs(s)) {
            ans++;
        }
    }

    // Ghi kết quả vào file output
    cout << ans << endl;

    return 0;
}

Pascal

program asum;

const
  MAX_N = 100000;
  MAX_S = 100000;

var
  N, S: integer;
  a: array[1..MAX_N] of integer;
  f: array[0..MAX_N] of int64;
  g: array[0..MAX_N] of int64;
  i, j: integer;
  cnt: int64;
  inp, out: text;

begin
  assign(inp, 'ASUM.INP');
  assign(out, 'ASUM.OUT');
  reset(inp);
  rewrite(out);

  readln(inp, N, S);
  for i := 1 to N do
    read(inp, a[i]);

  f[0] := 0;
  g[0] := 1;
  cnt := 0;

  for i := 1 to N do begin
    f[i] := f[i-1] + a[i];
    g[i] := g[i-1];
    while (f[i] - f[j-1] > S) and (j <= i) do begin
      g[i] := g[i] - g[j-1];
      f[i] := f[i] - a[j];
      j := j + 1;
    end;
    if f[i] - f[j-1] = S then
      cnt := cnt + g[j-1];
  end;

  writeln(out, cnt);

  close(inp);
  close(out);
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 *