Thời gian để một người có sức mạnh tiêu diệt được một quái vật có lượng máu H là Tương tự để một quái vật có sức mạnh có thể tiêu diệt được một người có lượng máu là.. Ta cần người tiêu
Trang 1HỘI CÁC TRƯỜNG THPT CHUYÊN
KHU VỰC DUYÊN HẢI, ĐỒNG BẰNG BẮC BỘ
KỲ THI CHỌN HỌC SINH GIỎI LẦN THỨ XII
MÔN THI: TIN HỌC – KHỐI 11
Ngày thi 14/07/2022
(Hướng dẫn thuật toán này gồm có 02 trang)
HƯỚNG DẪN THUẬT TOÁN ĐỀ THI ĐỀ XUẤT
Bài 1 (6 điểm) Xâu con.
Sử dụng Quy hoạch động:
- Gọi mảng là số kí tự có thể đến được từ đỉnh (1, 1
- Bạn có thể quy hoạch động bằng sắp xếp topo Bạn có thể sử dụng để
mô tả số lượng cạnh kết thúc ở Khởi tạo với tất cả trong hàng đợi
- Khi hàng đợi không rỗng thực hiện các bước sau:
o Lấy 1 đỉnh ở đầu hàng đợi.
o Lặp lại tất cả các cạnh kết thúc tại đỉnh Khi đó để tính cần tính
với 1
Cuối cùng giảm đi Nếu thì ta thêm điểm vào hàng đợi
o Biến đếm tăng lên 1.
- Khi đồ thị không có chu trình thì hàng đợi rỗng với Khi đó đáp án là
Nếu đồ thị có chu trình thì không thể bằng , ta in ra
- Độ phức tạp:
Bài 2 (7điểm)
Thời gian để một người có sức mạnh tiêu diệt được một quái vật có lượng máu H
là
Tương tự để một quái vật có sức mạnh có thể tiêu diệt được một người có lượng máu là
Ta cần người tiêu diệt quái vật trước
Vậy nếu một người có thể đánh bại được quái vật khi
Sub1:
Trang 2Ta chỉ thuê được mỗi người mỗi nhóm, vì vậy ta chuẩn bị một biến lấy tất
cả
Với mỗi quái vật , nếu
Nếu
Độ phức tạp:
Sub2:
Vì khá nhỏ nên ta cần xét mọi trường hợp
Với mỗi quái vật , ta duyệt từng nhóm và chọn người nhóm này thỏa mãn Lúc này sức mạnh của nhóm sẽ là
Nếu Thì ta sẽ lấy của lượng tiền bỏ ra
Độ phức tạp:
Sub3:
Với sub này, mỗi truy vấn ta cần dùng một thuật toán đủ nhanh chạy trong hoặc Ở đây tôi đề xuất thuật toán tìm kiếm nhị phân và quy hoạch động
Gọi là chỉ số sức mạnh của một nhóm hoặc 1 quái vật
Gọi là lượng lớn nhất có thể đạt được khi bỏ ra đồng
Với mỗi đội , ta khởi tạo
Đoạn công thức truy hồi ta làm như sau:
for (int i = 1; i <= C; i++)
for (int j = i, cnt = 1; j <= C; j += i, cnt++)
dp[j] = max(dp[j], 1ll * dp[i] * cnt);
for (int i = 1; i <= C; i++) dp[i] = max(dp[i], dp[i - 1]);
Đoạn code trên có ý nghĩa, dùng đồng để được một lượng dùng đồng sẽ được một lượng
Cuối cùng với mỗi quái vật j, ta chỉ cần tìm kiếm nhị phân số tiền ít nhất sao cho
Trang 3Độ phức tạp:
Bài 3 (7 điểm): TREE
Sub1:
Vì n, m khá nhỏ Nên sub này ta có thể duyệt cây với từng truy vấn
Với truy vấn 1 ta duyệt từng đỉnh trong cây con gốc v và gán lại màu cho nó Với truy vấn 2 ta chuẩn bị một biến Duyệt từng đỉnh trong cây con gốc v Mỗi đỉnh x có màu c, Và kết quả là số lượng bit 1 trong mask
ĐPT:
Sub2:
Vì cây là một đường thẳng kéo dài từ , nút sau là con của nút trước (i + 1 là con của i) Nên sub này ta sẽ xử lí như với một mảng gồm n phần tử bình thường
Vì có khá nhiều truy vấn và phần tử cần được gán, nên sub này cần sử dụng một CTDL có thể cập nhật và truy vấn đoạn một cách dễ dàng Ở đây, tôi đề xuất segment tree
Mỗi nút của segment tree sẽ lưu một bit x là các màu của đoạn mà nút này đè lên Với truy vấn 1, ta gán đoạn từ v -> n thành c
Với truy vấn 2, ta cũng chuẩn bị một mask để OR tất cả các đoạn từ v -> n trên cây segment tree lại Kết quả là số lượng bit 1 trong mask
ĐPT:
Sub3:
Phần CTDL ta dùng y hệt sub2 Nhưng ở đây, ta phải duỗi cây thành dạng một đường thẳng theo thời gian vào ra của từng nút
Với truy vấn 1, ta gán đoạn từ time_in[v] time_out[v] thành c
Với truy vấn 2, ta cũng dùng mask OR trong đoạn time_int[v] time_out[v]
ĐPT:
- Hết