Olympic 10 Thành phố 2024 - 2025¶
Bài 1: Năng lượng¶
Đề bài¶
An có quỹ thời gian \(N\) ngày để luyện tập cho kỳ thi. Do đó, An phải lập thời khóa biểu cho \(N\) buổi tối mà trong mỗi buổi An sẽ luyện tập hoặc ngủ sớm.
Mỗi tối, nếu An ngủ sớm thì năng lượng sẽ tăng lên \(A\) đơn vị, nếu An luyện tập thì năng lượng sẽ giảm \(B\) đơn vị.
An muốn luyện tập nhiều nhất có thể và cũng muốn duy trì mức năng lượng như trước khi bắt đầu luyện tập, nghĩa là mức năng lượng sẽ không giảm và cũng không tăng. An nhận định rằng muốn duy trì năng lượng thì tổng độ giảm phải bằng tổng độ tăng.
Yêu cầu: Hãy viết chương trình giúp An lập thời khóa biểu thỏa điều kiện trên.
Đầu vào: NANGLUONG.INP
- Dòng đầu tiên ghi số nguyên dương \(N (1 \le N \le 10^6)\).
- Dòng thứ hai ghi số nguyên dương \(A (1 \le A \le 10^3)\).
- Dòng thứ ba ghi số nguyên dương \(B (1 \le B \le 10^3)\).
Đầu ra: NANGLUONG.OUT
Một số nguyên là số buổi An sẽ luyện tập. Nếu An không thể lập thời khóa biểu theo yêu cầu trên thì ghi \(-1\).
Ví dụ:
| NANGLUONG.INP | NANGLUONG.OUT | Giải thích |
|---|---|---|
| 4 6 2 |
3 | Với quỹ thời gian 4 buổi, An sẽ luyện tập 3 buổi (giảm 3 * 2 = 6 đơn vị) và ngủ sớm 1 buổi (tăng 1 * 6 = 6 đơn vị). Thời khóa biểu này bảo đảm sau 4 buổi tối mức năng lượng không tăng và cũng không giảm. |
| 2 1 2 |
-1 |
Cách giải đề xuất¶
Ý tưởng chính
Gọi \(p\) (practice) là số ngày luyện tập, \(s\) (sleep) là số ngày ngủ sớm.
Ta có:
Tổng số ngày là: \(p + s = n\)
Tổng năng lượng không đổi: \(a . s = b . p\)
Từ hai đẳng thức trên, suy ra:
Như vậy, bài toán ban đầu có thể được phát biểu thành bài toán tìm \(p\) sao cho \(p\) là số nguyên dương, tức \(a . n\) chia hết cho \(a + b\).
Viết chương trình
Mã nguồn¶
Code đầy đủ được đặt tại:
Bài 2: Bội ba¶
Đề bài¶
Em Na học toán và rất thích các số bội ba (là các số chia hết cho 3). Để rèn luyện thêm, bạn An cho một dãy \(n\) các số nguyên dương và yêu cầu Na biến đổi n số đó thành các số bội ba nhưng phải theo nguyên tắc của An.
Na chỉ được biến đổi các số theo thứ tự từ trái qua phải. Đồng thời, tại mỗi vị trí, Na chỉ được cộng một giá trị nào đó vào số đang xét để biến nó thành số bội ba. Khi đó, tất cả các số phía sau đó cũng được cộng một giá trị tương ứng.
Yêu cầu: Hãy viết chương trình tính tổng giá trị được cộng thêm ít nhất để biến tất cả các số trong dãy thành số bội ba.
Đầu vào: BOIBA.INP
- Dòng đầu tiên chứa số nguyên dương \(n (1 \le n \le 2.10^5)\).
- Dòng tiếp theo chứa n số nguyên dương \(a_i (1 \le a_i \le 10^9)\).
Đầu ra: BOIBA.OUT
Một số nguyên là tổng giá trị cần tìm.
Ràng buộc:
- 60% số điểm của bài: \(n \le 10^3\)
- 40% số điểm của bài: \(n \le 2.10^5\)
Ví dụ:
| BOIBA.INP | BOIBA.OUT | Giải thích |
|---|---|---|
| 4 1 4 3 2 |
1 | Thực hiện theo thứ tự từ trái qua phải, dãy ban đầu 1 4 3 2 - Số 1 cần cộng 2 và phải cộng cho 3 số còn lại, giá trị phải dùng 2 x 4 số = 8, dãy mới: 3 6 5 4 - Số 6 là bội 3, bỏ qua không cần cộng, dãy vẫn là 3 6 5 4 - Số 5 cần cộng 1, giá trị phải dùng 1 x 2 số = 2, dãy mới: 3 6 6 5 - Số 5 cần cộng 1, giá trị phải dùng 1 x 1 số = 1, dãy mới: 3 6 6 6 Tổng giá trị đã cộng ở các vị trí: 8 + 2 + 1 = 11. |
Cách giải đề xuất¶
Ý tưởng chính
Tại phần tử a[i] đang xét, nhằm tránh dùng thêm một vòng lặp để thực hiện cộng thêm vào các phần tử sau a[i], ta xử lý như sau:
-
Đặt biến
xlà giá trị cần bù vào để một phần tửa[i]chia hết cho 3. -
Đặt biến phụ
cumulativedùng để lưu trữ giá trị tích lũy mà sẽ cộng thêm cho phần tử liền saua[i]:cumulative += xvànew_ai = ai + cumulative. -
Kết quả output (tức tổng giá trị cộng thêm cho tất cả phần tử) được tính dựa trên số lượng phần tử từ vị trí
iđến cuối mảng:result += x * (n - i).
Viết chương trình
Mã nguồn¶
Code đầy đủ được đặt tại:
Bài 3: Lát gạch¶
Đề bài¶
Quảng trường hình chữ nhật của thành phố ByteCity có kích thước \(m \times n\). Quảng trường được lát bằng \(m \times n\) viên gạch vuông kích thước \(1 \times 1\).
Sau một thời gian, những viên gạch cần được thay mới để đẹp hơn. Ban quản lý có \(T\) viên gạch mới. Do không đủ số lượng gạch cần thiết nên họ quyết định chỉ thay mới những viên gạch nằm dọc theo đường biên của quảng trường, phần gạch còn lại ở trung tâm vẫn giữ nguyên như cũ. Lưu ý độ rộng của đường biên luôn bằng nhau ở các cạnh.
Yêu cầu: Hãy viết chương trình cho biết độ rộng tối đa của đường biên có thể thay mới được khi sử dụng không quá \(T\) viên gạch.
Đầu vào: LATGACH.INP
Gồm một dòng ghi 3 số nguyên dương \(m, n, T (3 \le m, n \le 10^9, 1 \le T < m \times n)\).
Đầu ra: LATGACH.OUT
Một số nguyên là độ rộng tối đa cần tìm.
Ràng buộc:
- 70% số điểm của bài: \(3 \le m, n \le 10^6\).
- 30% số điểm của bài: không ràng buộc gì thêm.
Ví dụ:
| LATGACH.INP | LATGACH.OUT | Giải thích |
|---|---|---|
| 5 7 33 | 2 | Với quảng trường 5 x 7, dùng 32 viên gạch lát được đường biên có độ rộng bằng 2. |
| 6 6 32 | 2 | Với quảng trường 6 x 6, dùng 32 viên gạch lát được đường biên có độ rộng bằng 2. |
Cách giải đề xuất¶
Ý tưởng chính
Gọi \(w\) (weight) là độ rộng của đường biên, tức phần lát gạch.
Ta có:
-
Diện tích (hoặc số viên gạch cần lát) của toàn bộ quảng trường là: \(m \times n\)
-
Diện tích phần không lát gạch nằm ở giữa quảng trường là: \((m - 2w) \times (n - 2w)\)
-
Diện tích lát gạch (hoặc số viên gạch cần lát) là: \(m \times n - (m - 2w) \times (n - 2w)\)
Rút gọn thành: \(2w(m + n - 2w)\)
Như vậy, bài toán ban đầu có thể được phát biểu thành bài toán tìm \(w\) lớn nhất sao cho \(2w(m + n - 2w) \le t\).
Viết chương trình
0. Vì phép nhân trong phần trình bày trên có thể tạo ra giá trị rất lớn, ta cần sử dụng kiểu unsigned long long trong C++.
1. Viết hàm kiểm tra số gạch nằm trong giới hạn cho phép \(2w(m + n - 2w) \le t\).
2. Áp dụng ý tưởng tìm kiếm nhị phân để tìm \(w\) lớn nhất.
Mã nguồn¶
Code đầy đủ được đặt tại:

