Đề thi HSG môn Tin học tỉnh Yên Bái năm học 2024 – 2025 (Có đáp án Full Code)

Phần 1. Đề thi

Câu 1. (6,0 điểm) Mật khẩu

An đạt thành tích cao trong học tập nên được bố thưởng cho một đĩa cài đặt các khóa học nâng cao. Nhà sản xuất đã cung cấp cho An một mã số là một số nguyên dương N có không quá 255 chữ số. Để cài đặt được phần mềm, An phải nhập vào mật khẩu của phần mềm. Mật khẩu là một số nguyên dương M được tạo ra bằng cách tính tổng giá trị các chữ số của N.

Yêu cầu: Cho số nguyên dương N. Hãy tìm số nguyên dương M.

Dữ liệu: Vào từ tệp văn bản MATKHAU.INP ghi số nguyên dương N.

Kết quả: Ghi ra tệp văn bản MATKHAU.OUT số nguyên dương M tìm được.

Ví dụ:

MATKHAU.INPMATKHAU.OUT
8491538824759

Ràng buộc:

  • Có 80% test ứng với N≤108.
  • Có 20% test khác ứng với N≤10255

Câu 2. (5,0 điểm) Số có 3 ước số

An rất yêu thích tìm hiểu về các số có tính chất đặc biệt. Bạn ấy phát hiện ra là ngoài số nguyên tố có đúng 2 ước số nguyên dương thì còn có một loại số đặc biệt khác chỉ có đúng 3 ước số nguyên dương. An đang loay hoay tìm cách đếm xem trong đoạn từ số D đến số C cho trước sẽ có bao nhiêu số có 3 ước số như thế.

Yêu cầu: Giúp An tìm số lượng số có 3 ước số trong đoạn từ D đến C.

Dữ liệu: Tệp văn bản SO3UOC.INP chứa hai số nguyên dương D,C (D≤C≤109), các số cách nhau dấu cách.

Kết quả: Tệp văn bản SO3UOC.OUT ghi một số là số lượng các số có đúng 3 ước đã đếm được.

Ví dụ

SO3UOC.INPSO3UOC.OUTGiải thích
10 1002Trong đoạn [10, 100] có 2 số có đúng 3 ước số là: 25, 49.

Ràng buộc

  • 40% số test với D,C≤104.
  • 40% số test với D,C≤106.
  • 20% số test với D,C≤109.

Câu 3. (5,0 điểm) Số trang

An thực hiện đánh số trang cho quyển vở có N trang của mình bằng các giá trị liên tiếp từ 1 đến N. An muốn tính trước số lượng chữ số 0, số 1, số 2, …, số 9 cần dùng.

Dữ liệu: Tệp văn bản SOTRANG.INP ghi số nguyên dương N.

Kết quả: Tệp văn bản SOTRANG.OUT gồm 10 dòng,

  • Dòng thứ nhất là số lượng chữ số 0 cần dùng.
  • Dòng thứ hai là số lượng chữ số 1 cần dùng.
  • Dòng thứ mười là số lượng chữ số 9 cần dùng.

Ví dụ

SOTRANG.INPSOTRANG.OUT
150 1
1 8
2 2
3 2
4 2
5 2
6 1
7 1
8 1
9 1

Ràng buộc

  • 80% số test ứng với N≤103.
  • 20% số test còn lại ứng với N≤105.

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

Trong học kỳ I vừa qua, bạn An đã đạt thành tích cao trong học tập. Bạn được bố mẹ cho phép chọn các phần thưởng cho mình. Các phần thưởng được xếp thành một dãy và được đánh số từ 1 đến N, phần thưởng thứ i có giá trị là ai​ (1≤i≤N). An được chọn các phần thưởng của mình theo nguyên tắc không được chọn x phần thưởng liên tiếp nhau trong dãy.

Yêu cầu: Viết chương trình để máy tính hướng dẫn An chọn các phần thưởng theo nguyên tắc trên sao cho tổng giá trị của các phần thưởng nhận được là lớn nhất.

Dữ liệu: Tệp văn bản PTHUONG.INP gồm các dòng:

  • Dòng 1: Ghi số nguyên dương N là số phần thưởng và giá trị x (2≤x<N≤106).
  • Dòng 2: Ghi N số nguyên dương ai​ là giá trị của các phần thưởng (ai≤109,1≤i≤N).

Kết quả: Ghi ra tệp văn bản PTHUONG.OUT tổng giá trị lớn nhất của các phần thưởng được chọn.

Ví dụ

PTHUONG.INPPTHUONG.OUT
5 323
6 9 1 3 5

Giải thích:

  • Chọn các phần thưởng có giá trị 6 và 5, tổng giá trị là 6 + 5 = 23.

Ràng buộc:

  • 30% số test ứng với x = 3; x < N ≤ 20.
  • 30% số test ứng với x = 3; x < N ≤ 106.
  • 40% số test khác ứng với 2 ≤ x <10; x < N ≤ 106.

Phần 2. Code tham khảo (C++)

Câu 1. (6,0 điểm) Mật khẩu

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

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

    string N; // Lưu số N dưới dạng chuỗi
    cin >> N;

    int M = 0; // Biến lưu tổng các chữ số
    for (char c : N) {
        M += (c - '0'); // Chuyển ký tự thành số và cộng vào tổng
    }

    cout << M; // Ghi kết quả ra file MATKHAU.OUT

    return 0;
}

Câu 2. (5,0 điểm) Số có 3 ước số

Lưu ý: Đặc điểm của số có 3 ước số:

  • Một số nguyên dương n có đúng 3 ước số khi và chỉ khi nó là bình phương của một số nguyên tố .
  • Ví dụ:
    • Số 4=2^2 có các ước số: 1,2,4 (đúng 3 ước).
    • Số 9=3^2 có các ước số: 1,3,9 (đúng 3 ước).
    • Số 25=5^2 có các ước số: 1,5,25 (đúng 3 ước).
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

// Hàm sàng Eratosthenes để tìm tất cả số nguyên tố <= maxP
vector<bool> sieve(int maxP) {
    vector<bool> isPrime(maxP + 1, true);
    isPrime[0] = isPrime[1] = false; // 0 và 1 không phải số nguyên tố
    for (int i = 2; i * i <= maxP; ++i) {
        if (isPrime[i]) {
            for (int j = i * i; j <= maxP; j += i) {
                isPrime[j] = false;
            }
        }
    }
    return isPrime;
}

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

    long long D, C;
    cin >> D >> C;

    // Giới hạn trên của p là sqrt(C)
    int maxP = sqrt(C);
    vector<bool> isPrime = sieve(maxP);

    int count = 0;
    for (int p = 2; p <= maxP; ++p) {
        if (isPrime[p]) {
            long long pSquare = (long long)p * p;
            if (pSquare >= D && pSquare <= C) {
                count++;
            }
        }
    }

    cout << count;

    return 0;
}

Câu 3. (5,0 điểm) Số trang

#include <iostream>
#include <string>
using namespace std;

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

    int N;
    cin >> N;

    // Mảng đếm số lần xuất hiện của các chữ số từ 0 đến 9
    int count[10] = {0};

    // Duyệt qua từng số từ 1 đến N
    for (int i = 1; i <= N; ++i) {
        int num = i;
        while (num > 0) {
            int digit = num % 10; // Lấy chữ số cuối cùng
            count[digit]++;
            num /= 10; // Loại bỏ chữ số cuối cùng
        }
    }

    // Ghi kết quả vào tệp SOTRANG.OUT 
    for (int i = 0; i < 10; ++i) {
        cout << i << " " << count[i] << endl;
    }

    return 0;
}

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

#include <iostream>
#include <vector>
using namespace std;

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

    int N, x;
    cin >> N >> x;

    vector<long long> a(N + 1); // Mảng lưu giá trị các phần thưởng
    for (int i = 1; i <= N; ++i) {
        cin >> a[i];
    }

    // Mảng dp để lưu tổng giá trị lớn nhất tại mỗi vị trí
    vector<long long> dp(N + 1, 0);

    // Biến max_prev để lưu giá trị lớn nhất của dp[j] trong khoảng [1, i-x]
    long long max_prev = 0;

    for (int i = 1; i <= N; ++i) {
        if (i > x) {
            max_prev = max(max_prev, dp[i - x]);
        }
        dp[i] = max(dp[i - 1], a[i] + max_prev);
    }

    // Kết quả là giá trị lớn nhất trong dp[N]
    cout << dp[N];

    return 0;
}

Phần 3. Code tham khảo (Python)

Câu 1. (6,0 điểm) Mật khẩu

# Đọc dữ liệu từ file MATKHAU.INP
with open("MATKHAU.INP", "r") as f:
    N = f.read().strip()

# Tính tổng các chữ số của N
M = sum(int(digit) for digit in N)

# Ghi kết quả vào file MATKHAU.OUT
with open("MATKHAU.OUT", "w") as f:
    f.write(str(M))

Câu 2. (5,0 điểm) Số có 3 ước số

import math

# Hàm sàng Eratosthenes để tìm các số nguyên tố <= maxP
def sieve(maxP):
    isPrime = [True] * (maxP + 1)
    isPrime[0] = isPrime[1] = False
    for i in range(2, int(math.sqrt(maxP)) + 1):
        if isPrime[i]:
            for j in range(i * i, maxP + 1, i):
                isPrime[j] = False
    return isPrime

# Đọc dữ liệu từ file SO3UOC.INP
with open("SO3UOC.INP", "r") as f:
    D, C = map(int, f.read().split())

# Giới hạn trên của p là sqrt(C)
maxP = int(math.sqrt(C))
isPrime = sieve(maxP)

# Đếm số lượng số có 3 ước số trong đoạn [D, C]
count = 0
for p in range(2, maxP + 1):
    if isPrime[p]:
        pSquare = p * p
        if D <= pSquare <= C:
            count += 1

# Ghi kết quả vào file SO3UOC.OUT
with open("SO3UOC.OUT", "w") as f:
    f.write(str(count))

Câu 3. (5,0 điểm) Số trang

# Đọc dữ liệu từ file SOTRANG.INP
with open("SOTRANG.INP", "r") as f:
    N = int(f.read())

# Khởi tạo mảng đếm số lần xuất hiện của các chữ số từ 0 đến 9
count = [0] * 10

# Duyệt qua từng số từ 1 đến N
for num in range(1, N + 1):
    while num > 0:
        digit = num % 10
        count[digit] += 1
        num //= 10

# Ghi kết quả vào file SOTRANG.OUT
with open("SOTRANG.OUT", "w") as f:
    for i in range(10):
        f.write(f"{i} {count[i]}\n")

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

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

# Khởi tạo mảng dp và biến max_prev
dp = [0] * (N + 1)
max_prev = 0

# Tính toán dp[i] theo công thức quy hoạch động
for i in range(1, N + 1):
    if i > x:
        max_prev = max(max_prev, dp[i - x])
    dp[i] = max(dp[i - 1], a[i - 1] + max_prev)

# Ghi kết quả vào file PTHUONG.OUT
with open("PTHUONG.OUT", "w") as f:
    f.write(str(dp[N]))

Phần 4. Code tham khảo (Pascal)

Câu 1. (6,0 điểm) Mật khẩu

program MatKhau;
var
  N: AnsiString;
  i, M: Integer;
  inputFile, outputFile: Text;
begin
  // Đọc dữ liệu từ file MATKHAU.INP
  Assign(inputFile, 'MATKHAU.INP');
  Reset(inputFile);
  ReadLn(inputFile, N);
  Close(inputFile);

  // Tính tổng các chữ số của N
  M := 0;
  for i := 1 to Length(N) do
    M := M + Ord(N[i]) - Ord('0');

  // Ghi kết quả vào file MATKHAU.OUT
  Assign(outputFile, 'MATKHAU.OUT');
  Rewrite(outputFile);
  WriteLn(outputFile, M);
  Close(outputFile);
end.

Câu 2. (5,0 điểm) Số có 3 ước số

program SoCo3UocSo;
const
  MAX = 100000; // Giới hạn maxP = sqrt(10^9)
var
  isPrime: array[1..MAX] of Boolean;
  D, C, p, count, maxP: LongInt;
  inputFile, outputFile: Text;

procedure Sieve(maxP: LongInt);
var
  i, j: LongInt;
begin
  FillChar(isPrime, SizeOf(isPrime), True);
  isPrime[1] := False;
  for i := 2 to Trunc(Sqrt(maxP)) do
    if isPrime[i] then
      for j := i * i to maxP do
        if j mod i = 0 then
          isPrime[j] := False;
end;

begin
  // Đọc dữ liệu từ file SO3UOC.INP
  Assign(inputFile, 'SO3UOC.INP');
  Reset(inputFile);
  ReadLn(inputFile, D, C);
  Close(inputFile);

  // Giới hạn trên của p là sqrt(C)
  maxP := Trunc(Sqrt(C));
  Sieve(maxP);

  // Đếm số lượng số có 3 ước số trong đoạn [D, C]
  count := 0;
  for p := 2 to maxP do
    if isPrime[p] then
      if (p * p >= D) and (p * p <= C) then
        count := count + 1;

  // Ghi kết quả vào file SO3UOC.OUT
  Assign(outputFile, 'SO3UOC.OUT');
  Rewrite(outputFile);
  WriteLn(outputFile, count);
  Close(outputFile);
end.

Câu 3. (5,0 điểm) Số trang

program SoTrang;
var
  N, num, digit, i: LongInt;
  count: array[0..9] of LongInt;
  inputFile, outputFile: Text;
begin
  // Đọc dữ liệu từ file SOTRANG.INP
  Assign(inputFile, 'SOTRANG.INP');
  Reset(inputFile);
  ReadLn(inputFile, N);
  Close(inputFile);

  // Khởi tạo mảng đếm số lần xuất hiện của các chữ số từ 0 đến 9
  FillChar(count, SizeOf(count), 0);

  // Duyệt qua từng số từ 1 đến N
  for num := 1 to N do
  begin
    i := num;
    while i > 0 do
    begin
      digit := i mod 10;
      count[digit] := count[digit] + 1;
      i := i div 10;
    end;
  end;

  // Ghi kết quả vào file SOTRANG.OUT
  Assign(outputFile, 'SOTRANG.OUT');
  Rewrite(outputFile);
  for i := 0 to 9 do
    WriteLn(outputFile, i, ' ', count[i]);
  Close(outputFile);
end.

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

program PhanThuong;
const
  MAXN = 1000000; // Giới hạn N = 10^6
var
  N, x, i: LongInt;
  a: array[1..MAXN] of LongInt;
  dp: array[0..MAXN] of Int64;
  max_prev: Int64;
  inputFile, outputFile: Text;
begin
  // Đọc dữ liệu từ file PTHUONG.INP
  Assign(inputFile, 'PTHUONG.INP');
  Reset(inputFile);
  ReadLn(inputFile, N, x);
  for i := 1 to N do
    Read(inputFile, a[i]);
  Close(inputFile);

  // Khởi tạo mảng dp và biến max_prev
  dp[0] := 0;
  max_prev := 0;

  // Tính toán dp[i] theo công thức quy hoạch động
  for i := 1 to N do
  begin
    if i > x then
      max_prev := Max(max_prev, dp[i - x]);
    dp[i] := Max(dp[i - 1], a[i] + max_prev);
  end;

  // Ghi kết quả vào file PTHUONG.OUT
  Assign(outputFile, 'PTHUONG.OUT');
  Rewrite(outputFile);
  WriteLn(outputFile, dp[N]);
  Close(outputFile);
end.

Phần 5. Code tham khảo (Java)

Câu 1. (6,0 điểm) Mật khẩu

import java.io.*;

public class MatKhau {
    public static void main(String[] args) throws IOException {
        // Đọc dữ liệu từ file MATKHAU.INP
        BufferedReader reader = new BufferedReader(new FileReader("MATKHAU.INP"));
        String N = reader.readLine().trim();
        reader.close();

        // Tính tổng các chữ số của N
        int M = 0;
        for (char c : N.toCharArray()) {
            M += Character.getNumericValue(c);
        }

        // Ghi kết quả vào file MATKHAU.OUT
        BufferedWriter writer = new BufferedWriter(new FileWriter("MATKHAU.OUT"));
        writer.write(Integer.toString(M));
        writer.close();
    }
}

Câu 2. (5,0 điểm) Số có 3 ước số

import java.io.*;
import java.util.*;

public class SoCo3UocSo {
    public static void main(String[] args) throws IOException {
        // Đọc dữ liệu từ file SO3UOC.INP
        BufferedReader reader = new BufferedReader(new FileReader("SO3UOC.INP"));
        StringTokenizer st = new StringTokenizer(reader.readLine());
        long D = Long.parseLong(st.nextToken());
        long C = Long.parseLong(st.nextToken());
        reader.close();

        // Giới hạn trên của p là sqrt(C)
        int maxP = (int) Math.sqrt(C);
        boolean[] isPrime = new boolean[maxP + 1];
        Arrays.fill(isPrime, true);
        isPrime[0] = isPrime[1] = false;

        // Sàng Eratosthenes
        for (int i = 2; i * i <= maxP; i++) {
            if (isPrime[i]) {
                for (int j = i * i; j <= maxP; j += i) {
                    isPrime[j] = false;
                }
            }
        }

        // Đếm số lượng số có 3 ước số trong đoạn [D, C]
        int count = 0;
        for (int p = 2; p <= maxP; p++) {
            if (isPrime[p]) {
                long pSquare = (long) p * p;
                if (pSquare >= D && pSquare <= C) {
                    count++;
                }
            }
        }

        // Ghi kết quả vào file SO3UOC.OUT
        BufferedWriter writer = new BufferedWriter(new FileWriter("SO3UOC.OUT"));
        writer.write(Integer.toString(count));
        writer.close();
    }
}

Câu 3. (5,0 điểm) Số trang

import java.io.*;

public class SoTrang {
    public static void main(String[] args) throws IOException {
        // Đọc dữ liệu từ file SOTRANG.INP
        BufferedReader reader = new BufferedReader(new FileReader("SOTRANG.INP"));
        int N = Integer.parseInt(reader.readLine().trim());
        reader.close();

        // Khởi tạo mảng đếm số lần xuất hiện của các chữ số từ 0 đến 9
        int[] count = new int[10];

        // Duyệt qua từng số từ 1 đến N
        for (int num = 1; num <= N; num++) {
            int temp = num;
            while (temp > 0) {
                count[temp % 10]++;
                temp /= 10;
            }
        }

        // Ghi kết quả vào file SOTRANG.OUT
        BufferedWriter writer = new BufferedWriter(new FileWriter("SOTRANG.OUT"));
        for (int i = 0; i < 10; i++) {
            writer.write(i + " " + count[i] + "\n");
        }
        writer.close();
    }
}

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

import java.io.*;
import java.util.*;

public class PhanThuong {
    public static void main(String[] args) throws IOException {
        // Đọc dữ liệu từ file PTHUONG.INP
        BufferedReader reader = new BufferedReader(new FileReader("PTHUONG.INP"));
        StringTokenizer st = new StringTokenizer(reader.readLine());
        int N = Integer.parseInt(st.nextToken());
        int x = Integer.parseInt(st.nextToken());
        int[] a = new int[N];
        st = new StringTokenizer(reader.readLine());
        for (int i = 0; i < N; i++) {
            a[i] = Integer.parseInt(st.nextToken());
        }
        reader.close();

        // Khởi tạo mảng dp và biến max_prev
        long[] dp = new long[N + 1];
        long max_prev = 0;

        // Tính toán dp[i] theo công thức quy hoạch động
        for (int i = 1; i <= N; i++) {
            if (i > x) {
                max_prev = Math.max(max_prev, dp[i - x]);
            }
            dp[i] = Math.max(dp[i - 1], a[i - 1] + max_prev);
        }

        // Ghi kết quả vào file PTHUONG.OUT
        BufferedWriter writer = new BufferedWriter(new FileWriter("PTHUONG.OUT"));
        writer.write(Long.toString(dp[N]));
        writer.close();
    }
}