Học sinh giỏi 9 Khánh Hoà 2023 - 2024¶
Bài 1: Đếm gạo¶
Đề bài¶
Nấm thích truyện cổ tích. Đêm qua, Nấm nằm mơ về Lọ Lem. Lọ Lem không bị mụ dì ghẻ bắt phân loại đậu nữa mà bắt nhặt gạo.
Có rất nhiều gạo trong kho, các hạt gạo được đánh số thứ tự là số nguyên liên tiếp từ \(a\) đến \(b\). Mụ bắt nàng phải nhặt ra các hạt gạo có số thứ tự là bội của một số \(k\) cho trước. Đồng thời sau khi nhặt xong phải cho biết số lượng hạt gạo nhặt được.
Việc nhặt gạo thì đơn giản, bầy chim đã giúp nhặt xong. Nhiệm vụ của Lọ Lem là đếm số lượng. Thật không may, chưa đếm xong thì Nấm đã tỉnh dậy. Nấm rất muốn có câu trả lời cho Lọ Lem.
Yêu cầu: Hãy trả lời giúp Nấm là có bao nhiêu hạt gạo.
Dữ liệu vào: DEMGAO.INP
Gồm ba số nguyên dương \(a, b\) và \(k\) trên cùng một dòng \((1 \le a \le b < 10^{18}; 1 \le k \le 10^{18})\).
Kết quả: DEMGAO.OUT
Một số nguyên lẻ duy nhất là kết quả cần tìm.
Ví dụ:
DEMGAO.INP | DEMGAO.OUT | Giải thích |
---|---|---|
3 10 5 | 2 | Hai hạt gạo được nhặt là hạt số có thứ tự 5 và số thứ tự 10. |
6 9 5 | 0 | Không có hạt nào thoả mãn yêu cầu. |
Ràng buộc:
- 70% số test tương ứng với 70% số điểm có \(1 \le a \le b < 10^6\).
- 30% số test còn lại tương ứng 30% điểm số kkhông có ràng buộc gì thêm.
Bài giải đề xuất¶
Ý tưởng chính¶
Với \(n\) là một số nguyên dương, các bội của \(k\) mà không vượt quá \(n\) bao gồm những số sau: \(1k, 2k, 3k, ..., qk\)
Ta có: \(qk \le n \Rightarrow q \le \frac{n}{k}\).
Vì \(q\) có thể là các giá trị trong đoạn \([1..q]\) nên \(q\) cũng là số lượng các bội của \(k\) mà không vượt quá \(n\).
Như vậy, để tính số lượng bội của \(k\) trong đoạn \([a..b]\), ta thực hiện như sau:
- Tính số lượng bội của \(k\) trong đoạn \([1..b]\): \(\frac{b}{k}\) \((1)\)
- Tính số lượng bội của \(k\) trong đoạn \([1..a - 1]\): \(\frac{a - 1}{k}\) \((2)\)
- Số lượng bội của \(k\) trong đoạn \([a..b]\) là hiệu của \((1)\) và \((2)\).
Viết chương trình¶
Mã nguồn¶
Code đầy đủ được đặt tại GitHub.
Bài 2: Từ dài¶
Đề bài¶
Một từ được định nghĩa là một ký tự hoặc một dãy ký tự liên tiếp nhau và không chứa khoảng trắng. Độ dài của một từ là số ký tự có trong từ đó.
Cho xâu gồm các ký tự A..Z, a..z, 0..9 và ký tự khoảng trắng.
Yêu cầu: Tìm độ dài của từ có nhiều ký tự nhất và từ tương ứng với độ dài đó.
Dữ liệu vào: TUDAI.INP
Một dòng duy nhất chứa xâu. Độ dài xâu không quá 255 ký tự và trong xấu có ít nhất một từ.
Kết quả: TUDAI.OUT
- Dòng 1: độ dài của từ có nhiều ký tự nhất, tức độ dài lớn nhất.
- Dòng 2: từ mà có độ dài lớn nhất.
Nếu có nhiều từ có cùng độ dài lớn nhất thì ghi từ có độ dài lớn nhất sau cùng trong xâu.
Ví dụ:
TUDAI.INP | TUDAI.OUT |
---|---|
Khanh Hoa que huong toi | 5 huong |
Bài giải đề xuất¶
Ý tưởng chính¶
Để xử lý từng từ trong chuỗi input:
- Đối với C++, ta dùng kiểu dữ liệu
stringstream
.stringstream
giúp đọc các ký tự liên tiếp nhau cho đến khi gặp khoảng trắng hoặc đến khi hết dữ liệu. - Trong Python, ta dùng hàm
split()
để tách chuỗi thànhlist
các từ.
Viết chương trình¶
Mã nguồn¶
Code đầy đủ được đặt tại GitHub.
Bài 3: Cửa sổ¶
Đề bài¶
Tí đang chơi trò ghép nhà từ những que tính. Phần căn nhà đã được ghép xong, chỉ còn thiếu một cửa số hình chữ nhật.
Hiện tại, Tí còn dư n que tính. Các que được đánh số thứ tự từ \(1\) đến \(n\). Que thứ \(i\) có độ dài \(a_i\).
Tí muốn ghép được cửa sổ càng to càng tốt. Một cửa sổ sẽ được ghép từ 4 que.
Yêu cầu: Hãy cho biết chu vi của cửa sổ lớn nhất mà Tí có thể ghép được.
Không bẻ gãy hay chắp nối để thay đổi độ dài que. Hình vuông cũng được xem là hình chữ nhật.
Dữ liệu vào: CUASO.INP
- Dòng đầu chứa số nguyên dương \(n (1 \le n \le 10^6)\).
- Dòng thứ hai chứ \(n\) số nguyên dương \(a_i (1 \le a_i \le 10^6; 1 \le i \le n)\).
Kết quả: CUASO.INP
Số nguyên duy nhất là chua vi lớn nhất của cửa sổ có thể ghép được. Nếu không thể ghép được thì ghi \(-1\).
Ví dụ:
CUASO.INP | CUASO.OUT | Giải thích |
---|---|---|
7 3 8 4 3 8 1 1 |
22 | Có 3 cách ghép cửa sổ là: \((8, 3), (3, 1), (8, 1)\). Chu vi lớn nhất là \((8 + 3) \times 2 = 22\). |
5 4 9 1 9 3 |
-1 | Không thể ghép được cửa sổ nào. |
Bài giải đề xuất¶
Ý tưởng chính¶
- Dùng mảng tần số để lưu số lần xuất hiện của từng độ dài que.
- Độ dài nào xuất hiện trên 2 lần thì nạp vào mảng độ dài ứng viên (có thể đem ghép cửa sổ).
- Sắp xếp mảng ứng viên giảm dần. Lúc này, hai phần tử đầu tiên chính là hai độ dài lớn nhất, tức làm cho chu vi cửa sổ trở thành lớn nhất.
Viết chương trình¶
Bước 0:
Khởi tạo mảng tần số f
và các biến liên quan.
Bước 1:
Cập nhật mảng tần số f
.
Bước 2:
Độ dài nào xuất hiện hơn 2 lần thì nạp vào mảng ứng viên candidates
.
Nếu xuất hiện 4 lần thì nạp thêm lần nữa, do có thể ghép cửa sổ hình vuông.
Bước 3:
Nếu mỗi độ dài (mỗi phần tử) trong mảng ứng viên có đủ 2 loại trở lên thì thực hiện sắp xếp giảm dần. Rồi lấy ra hai phần tử đầu, chính là hai loại độ dài lớn nhất, để tính chu vi lớn nhất.
Mã nguồn¶
Code đầy đủ được đặt tại GitHub.
Bài 4: Số nguyên tố toàn diện¶
Đề bài¶
Số nguyên tố là số có đúng hai ước nguyên dương là 1 và chính nó.
Vốn là người sáng tạo, An đưa ra một khái niệm mới gọi là "số nguyên tố toàn diện". Một số nguyên dương x gọi là số nguyên tố toàn diện nếu thoả mãn đồng thời 3 điều kiện sau:
- x là số nguyên tố.
- Lần lượt bỏ đi các chữ số bên phải của x thì phần còn lại của nó vẫn là số nguyên tố.
- Thêm vào bên phải của x một trong các chữ số từ 0 đến 9, số thu được cũng là số nguyên tố.
Ví dụ: 313 là số nguyên tố toàn diện vì:
- 313 là nguyên tố.
- Bỏ đi số 3 bên phải, ta còn số 31, là số nguyên tố. Bỏ tiếp đi số 1, ta còn số 3, cũng là số nguyên tố.
- Thêm số 7 vào sau 313, ta được số 3137 là số nguyên tố.
Yêu cầu: cho dãy A gồm \(n\) số nguyên dương \(a_1, a_2, ..., a_n\) và \(m\) câu hỏi. Mỗi câu hỏi có dạng \((u, v)\) với ý nghĩa: đếm số lượng số nguyên tố toàn diện trong dãy A từ vị trí \(u\) đến \(v\).
Dữ liệu vào: SNTOTD.INP
- Dòng đầu chứ số nguyên \(n (1 \le n \le 10^5)\).
- Dòng thứ hai chứa \(n\) số nguyên dương \(a_1, a_2, ..., a_n (1 \le a_i \le 10^6; 1 \le i \le n)\).
- Dòng thứ ba chứa số nguyên \(m\) là số lượng câu hỏi \((1 \le m \le 10^5)\).
- \(m\) dòng tiếp theo, mỗi dòng chứa hai số nguyên dương \(u, v (1 \le u \le v \le n)\).
Kết quả: SNTOTD.OUT
Gồm \(m\) dòng, mỗi dòng là đáp án của một câu hỏi theo thứ tự của các câu hỏi được đưa ra trong dữ liệu vào.
Ví dụ:
SNTOTD.INP | SNTOTD.OUT | Giải thích |
---|---|---|
6 59 12 57 53 23 313 3 1 3 2 5 3 6 |
1 1 2 |
Có 1 số nguyên tố toàn diện là 59 trong đoạn từ 1 đến 3. Có 1 số nguyên tố toàn diện là 23 trong đoạn từ 2 đến 5. Có 2 số nguyên tố toàn diện là 23 và 313 trong đoạn từ 3 đến 6. |
Ràng buộc:
- 70% số test tương ứng với 70% số điểm có \(1 \le n \le 10^3; 1 \le a_i \le 10^3\).
- 30% số test còn lại tương ứng với 30% số điểm không có ràng buộc gì thêm.
Bài giải đề xuất¶
Ý tưởng chính¶
- Dùng sàng Eratosthenes để kiểm tra các điều kiện liên quan đến nguyên tố.
- Viết ba hàm kiểm tra ứng với ba điều kiện nguyên tố của đề bài.
- Viết một hàm nữa, gọi ba hàm vừa viết trên nhằm xác định số nguyên tố toàn diện.
- Dùng mảng cộng dồn (prefix sum) để tính số lượng số nguyên tố toàn diện theo từng truy vấn (câu hỏi).
Viết chương trình¶
Bước 0:
Đặt giới hạn trên cho sàng Eratosthenes và các biến liên quan.
Bước 1:
Viết hàm để khởi tạo sàng Eratosthenes.
Bước 2:
Viết ba hàm kiểm tra từng điều kiện thoả mãn số nguyên tố toàn diện.
-
Từ khoá
inline
làm cho trình biên dịch thay thế lời gọi hàm bằng toàn bộ đoạn mã của thân hàm tại vị trí gọi hàm.Mục đích chính là tăng tốc độ thực thi chương trình bằng cách loại bỏ chi phí liên quan đến việc gọi hàm. Chi phí này bao gồm:
- Chuẩn bị stack
- Nhảy (jump)
- Thực thi hàm
- Trả về giá trị
- Dọn dẹp stack
- Nhảy về
Bước 3:
Viết hàm kiểm tra số nguyên tố toàn diện bằng cách gọi thực thi ba hàm trên.
Bước 4:
Đọc dữ liệu vào, cập nhật giá trị của mảng tổng cộng dồn và tính kết quả của các truy vấn (câu hỏi).
Mã nguồn¶
Code đầy đủ được đặt tại GitHub.