2021 Olympic 11¶
Câu 1: Tam giác vuông (10 điểm)¶
Đề bài¶
Nam vẫn thường hướng dẫn em trai mình, bé An, học bài mỗi ngày. Hôm nay Nam muốn giới thiệu cho An biết về các hình tam giác. Nam đặt trên một mặt phẳng \(N\) điểm phân biệt. Tiếp đến Nam chọn ra 3 điểm không thẳng hàng, nối chúng lại và giới thiệu với An rằng 3 đoạn thẳng nối 3 điểm phân biệt không thẳng hàng thì tạo thành một tam giác.
Theo hướng dẫn của Nam, An đã vẽ được rất nhiều hình tam giác trên mặt phẳng đó. Trong những hình tam giác có thể vẽ trên mặt phẳng, An chỉ thích vẽ những tam giác vuông có các cạnh góc vuông (cạnh kề với góc vuông) song song với trục hoành và trục tung. An hỏi Nam rằng mình có thể vẽ được bao nhiêu hình tam giác vuông như thế với \(N\) điểm cho trước trên mặt phẳng. An không muốn làm em mình thất vọng nhưng việc trả lời chính xác câu hỏi trên quả là một thử thách dành cho Nam. Bạn hãy giúp Nam trả lời câu hỏi trên nhé.
Yêu cầu: Cho trước \(N\) điểm phân biệt trên mặt phẳng tọa độ Oxy. Hãy viết một chương trình cho biết từ \(N\) điểm trên có thể vẽ bao nhiêu tam giác vuông có các cạnh góc vuông song song với trục hoành và trục tung.
Dữ liệu: Vào từ tệp văn bản TGV.INP, gồm:
-
Dòng đầu ghi một số nguyên \(N\) cho biết số điểm phân biệt trên mặt phẳng \((3 \lt N \lt 100000)\).
-
\(N\) dòng tiếp theo, mỗi dòng ghi hai số nguyên \(X\), \(Y\) cách nhau một khoảng trắng cho biết tọa độ các điểm \((1 \lt X, Y \lt 100000)\).
Kết quả: Ra tập tin văn bản TGV.OUT một số nguyên là số lượng tam giác vuông theo yêu cầu trên.
Ví dụ:
TGV.INP | TGV.OUT |
---|---|
5 1 1 1 2 1 3 2 1 2 3 |
6 |
Bài giải đề xuất¶
Ý tưởng chính¶
Để tính số lượng tam giác vuông, ta cần tính số cạnh góc vuông, tức các cạnh song song với hai trục của hệ toạ độ:
- Để tính số cạnh song song với trục tung, ta tính số tung độ y có cùng hoành độ x.
- Để tính số cạnh song song với trục hoành, ta tính số hoành độ x có cùng tung độ y.
Với cùng một bộ (x, y), ta lấy tích của số cạnh song song trục tung và số cạnh song song trục hoành là đạt được số tam giác vuông tạo thành.
Viết chương trình¶
1. Nhập liệu
Khi đọc các dòng từ tập tin input, ta nạp vào danh sách kề x_axis
các tung độ có cùng hoành độ x
, và nạp vào danh sách kề y_axis
các hoành độ có cùng tung độ y
.
2. Xử lý
Duyệt từng hoành độ x
trong phạm vi [1..hoành độ cuối cùng]
, lặp thao tác:
- Tính số cạnh song song trục tung ứng với
x
đang xét. - Duyệt từng tung độ
y
trong danh sách kềx_axis[x]
, lặp thao tác:- Tính số cạnh song song trục hoành ứng với
y
đang xét. - Nhân số cạnh song song với nhau để ra được số tam giác vuông ứng với
x
vày
đang xét.
- Tính số cạnh song song trục hoành ứng với
Mã nguồn¶
Code đầy đủ được đặt tại GitHub.
Câu 2: Khoảng cách (10 điểm)¶
Đề bài¶
Ngành công an đang tích cực thực hiện việc cấp thẻ căn cước công dân (CCCD). Việc cấp thẻ CCCD cho hàng triệu người nhưng vẫn đảm bảo an toàn phòng chống dịch theo khuyến cáo 5K của bộ Y tế đòi hỏi ngành công an phải có những giải pháp phù hợp.
Ban tổ chức (BTC) việc cấp thẻ CCCD đã cho dựng trong khu vực chờ một dãy có \(N\) ghế được đánh số liên tiếp từ \(1\) đến \(N\). Khoảng cách giữa hai ghế, ghế \(A\) có số \(D_A\), ghế số \(B\) có số \(D_B\), được tính bằng trị tuyệt đối của hiệu (\(D_A - D_B)\).
Để giữ khoảng cách tối ưu cho người dân trong khu vực chờ, BTC khuyến cáo người dân khi vào khu vực chờ cần chọn ghế ngồi có khoảng cách với ghế gần nhất có người đang ngồi trong khu vực chờ là lớn nhất. Nếu có nhiều ghế thỏa điều kiện trên, người dân sẽ chọn ghế ngồi có số bé nhất. Người đầu tiên vào khu vực chờ sẽ luôn chọn ghế số 1. Khi đã chọn được một ghế ngồi, người dân sẽ không đổi chỗ cho đến khi rời khỏi khu vực chờ. BTC muốn nhờ bạn viết một chương trình tự động xác định vị trí ghế ngồi theo yêu cầu trên mỗi khi có một người vào khu vực chờ.
Yêu cầu: Cho trước dãy các sự kiện vào hoặc ra khu vực chờ, bạn hãy viết một chương trình xác định vị trí ghế ngồi (thông qua số của ghế) cho từng người mỗi khi vào khu vực chờ, biết rằng ban đầu khu vực chờ trống.
Có \(M\) sự kiện được đánh số thứ tự từ \(1\) đến \(M\) theo thời gian xảy ra. Mỗi sự kiện thuộc một trong hai loại: sự kiện 'V' để biết một người vào khu vực chờ, sự kiện 'R' cho biết một người rời khu vực chờ. Với mỗi sự kiện 'R', bạn được cho biết thêm một số nguyên \(X\) với ý nghĩa người rời khu vực chờ trong sự kiện này là người đã vào khu vực chờ ở sự kiện thứ \(X\). Bạn có thể giả sử dữ liệu cho luôn hợp lý (không có người chưa vào đã rời khu vực chờ, khu vực chờ luôn còn chỗ cho người mới vào).
Dữ liệu: Vào từ tập tin văn bản YTE5K.INP, gồm:
-
Dòng đầu là hai số nguyên \(N\) và \(M\) cách nhau một khoảng trắng \((1 \lt N \lt 150000, 1 \lt M \lt 30000)\) lần lượt là số ghế trong khu vực chờ và số sự kiện.
-
Trên \(M\) dòng tiếp theo, dòng thứ \(K\) mô tả sự kiện thứ \(K\), có thể là một ký tự 'V' hoặc một ký tự 'R' theo sau là một khoảng trắng và một số nguyên \(X (1 \lt X \lt K)\).
Kết quả: Ra tập tin văn bản YTE5K.OUT, với mỗi sự kiện 'V' theo thứ tự xuất hiện trong file dữ liệu hãy xuất trên một dòng cho biết vị trí ghế ngồi thỏa điều kiện đề bài.
Ghi chú: Có 70% số lượng test chỉ có sự kiện 'V'.
Ví dụ:
YTE5K.INP | YTE5K.INP |
---|---|
10 5 V V V R 1 V |
1 10 5 3 7 |
YTE5K.INP | YTE5K.OUT |
---|---|
10 8 V V V V R 2 R 1 V V |
1 10 5 3 10 1 |
Bài giải đề xuất¶
Ý tưởng chính¶
Ứng với mỗi sự kiện, ta lần lượt xét hai trường hợp là sự kiện loại 'V'
hay 'R'
.
Trường hợp 1: Sự kiện 'V'
Ứng với mỗi ghế còn trống c
, ta tìm khoảng cách gần nhất trong số các khoảng cách tính từ ghế c
này đến các ghế đã có người ngồi.
Trong số các khoảng cách gần nhất, ta tìm khoảng cách lớn nhất và ghi nhận ghế c
tương ứng. Nếu có nhiều ghế c
thoả khoảng cách lớn nhất, ta chọn ghế có số c
nhỏ nhất.
Trường hợp 2: Sự kiện 'R'
Ta chỉ cần đặt lại giá trị mới cho các biến liên quan.
Viết chương trình¶
1. Khai báo các biến cần dùng:
2. Khởi tạo giá trị 0
cho toàn bộ mảng ánh xạ sự kiện - ghế event_chair
.
Khởi tạo các biến khác ứng với yêu cầu đề bài "người đầu tiên vào khu vực chờ sẽ luôn chọn ghế số 1".
2. Duyệt từng sự kiện i
trong phạm vi [2..m]
, lặp thao tác xét sự kiện thuộc loại 'V'
hay 'R'
.
Trường hợp 1: Sự kiện 'V'
Duyệt từng ghế thứ c
(đã có lẫn chưa có người ngồi), lặp các thao tác:
-
Chỉ xét các ghế
c
chưa có người ngồi, tức chưa được đánh dấu trongoccupied_chairs
. -
Duyệt các ghế
oc
đã có người ngồi, lặp thao tác tìm khoảng cách gần nhất trong số các khoảng cách từ ghếc
đang xét đến các ghếoc
đã có người ngồi, lưu vào biếnnearest
. -
Nếu
nearest
lớn hơn khoảng cách lớn nhấtmax_distance
thì tạm ghi nhận giá trịmax_distance
mới và ghếc
là ghế được chọn. -
Nếu
nearest
bằng khoảng cách lớn nhấtmax_distance
thì chỉ ghi nhận ghế cóc
nhỏ hơn nhằm thoả yêu cầu đề bài "Nếu có nhiều ghế thoả điều kiện trên, người dân sẽ chọn ghế ngồi có số bé nhất."
Lưu ghế được chọn selected_chair
vào các mảng liên quan.
Trường hợp 2: Sự kiện 'R'
Ta đặt lại giá trị mới cho các biến liên quan.
- Dòng lệnh này chỉ mang tính tường minh và bảo đảm đúng trạng thái của mảng
event_chair
, chứ không ảnh hưởng kết quả xuất ra, vốn được lưu trong mảngresult
.
- Dòng lệnh này chỉ mang tính tường minh và bảo đảm đúng trạng thái của mảng
event_chair
, chứ không ảnh hưởng kết quả xuất ra, vốn được lưu trong mảngresult
.
Mã nguồn¶
Code đầy đủ được đặt tại GitHub.