| # | Bài tập | Điểm | Thời gian: | Giới hạn bộ nhớ |
|---|---|---|---|---|
| 1 | BOI 2023 - Astronomer | 100 (p) | 3.0s | 768M |
| 2 | BOI 2023 - Mineral Deposits | 100 (p) | 5.0s | 768M |
| 3 | BOI 2023 - Sequence | 100 (p) | 1.0s | 768M |
Nhà thiên văn học rất đam mê ngắm sao. Đặc biệt, ông vô cùng thích thú khi được ngắm đồng thời \(k\) ngôi sao qua kính thiên văn của mình. Chế tạo một kính thiên văn có bán kính \(r\) tốn \(t\cdot r\) krone. Khi vừa được chế tạo, kính thiên văn hướng đúng vào gốc tọa độ \((0,0)\). Việc chuyển kính sang hướng khác cũng tốn công sức: dịch chuyển điểm mà kính hướng tới một khoảng cách \(d\) tốn \(s\cdot d\) krone. Nhà thiên văn học có thể quan sát tất cả các ngôi sao cách điểm mà kính hướng tới không quá \(r\).
Chi phí nhỏ nhất để chế tạo và di chuyển kính thiên văn sao cho có thể quan sát đồng thời \(k\) ngôi sao là bao nhiêu?
Tất cả tọa độ và khoảng cách đều được xét trong mặt phẳng Euclid.
Dòng đầu tiên chứa bốn số nguyên \(k\), \(n\), \(s\), \(t\): số ngôi sao nhà thiên văn học muốn quan sát, số ngôi sao trên bầu trời đêm nay, chi phí dịch chuyển và chi phí chế tạo kính thiên văn.
\(n\) dòng tiếp theo mô tả các ngôi sao. Dòng thứ \(i\) chứa hai tọa độ nguyên \(x_i\) và \(y_i\) của ngôi sao thứ \(i\).
In một số thực: số krone ít nhất mà nhà thiên văn học cần chi trả.
Kết quả được chấp nhận nếu sai số tương đối hoặc sai số tuyệt đối so với đáp án đúng không vượt quá \(\epsilon=10^{-6}\), ngoại trừ phân nhóm 6 được nêu bên dưới.
Các bộ kiểm thử được chia thành các nhóm, mỗi nhóm có một số điểm. Để nhận được điểm của một nhóm, chương trình phải giải đúng tất cả các bộ kiểm thử trong nhóm đó. Điểm cuối cùng là điểm cao nhất của một lần nộp bài.
Ví dụ 1
2 3 1000 500
0 0
2 0
3 1
1000.0
Ví dụ 2
2 3 500 3000
0 0
2 0
3 1
3387.277541898787
Ví dụ 3
2 3 250 750
0 0
2 0
3 1
1000.0
Xét \(n=3\) ngôi sao tại các vị trí \((0,0)\), \((2,0)\) và \((3,1)\). Vùng tô màu trong hình biểu diễn một kính thiên văn có bán kính \(1\), hướng vào điểm \((1,0)\) và bao phủ hai ngôi sao. Phương án này tốn \(s+t\) krone và là một lời giải tối ưu cho ví dụ 3. Hình cũng biểu diễn các lời giải tối ưu cho các ví dụ 1, 2 và 4.
Ví dụ 4
2 3 0 500
0 0
2 0
3 1
353.55339059327395
Ví dụ 5
3 4 0 10
0 0
10 0
5 10
5 5
50.0
Bạn phụ trách xử lý tín hiệu cho một công ty khai khoáng ngoài Trái Đất, và tàu của bạn đang tiến đến một tiểu hành tinh. Các lần quét sơ bộ cho thấy có \(k\) mỏ khoáng sản trên tiểu hành tinh, nhưng chưa biết vị trí chính xác của chúng.
Bề mặt tiểu hành tinh có thể được xem như một lưới tọa độ nguyên. Mỗi mỏ khoáng sản nằm tại một vị trí có tọa độ nguyên chưa biết. Mỏ thứ \(i\) có tọa độ \((x_i,y_i)\) thỏa mãn \(-b\le x_i\le b\) và \(-b\le y_i\le b\), với \(b\) là một số nguyên tương ứng với phạm vi quét ban đầu.
Để xác định chính xác vị trí các mỏ khoáng sản, bạn có thể gửi các thiết bị thăm dò xuống bề mặt tiểu hành tinh. Các thiết bị được gửi theo từng đợt, mỗi đợt gồm nhiều thiết bị được gửi cùng lúc.
Giả sử bạn gửi một đợt gồm \(d\) thiết bị đến các tọa độ \((s_j,t_j)\) với \(1\le j\le d\). Khi đến nơi, mỗi thiết bị xác định khoảng cách Manhattan từ vị trí của nó đến từng mỏ trong số \(k\) mỏ khoáng sản và gửi các khoảng cách về tàu. Tất cả các gói dữ liệu đến cùng lúc, nên không thể xác định khoảng cách nào do thiết bị nào gửi về. Vì vậy, đợt thăm dò trả về \(k\cdot d\) khoảng cách nguyên
Bạn cần tìm vị trí các mỏ khoáng sản với số đợt thăm dò ít nhất có thể.
Bài này sử dụng giao diện hàm C++17. Hãy nộp mã nguồn có #include "mineraldeposits.h" và cài đặt hàm sau; tệp tiêu đề mineraldeposits.h được cung cấp kèm bài:
std::vector<std::pair<long long, long long>> find_deposits(int b, int k, int w);
Bộ chấm gọi find_deposits(b, k, w) đúng một lần cho mỗi bộ kiểm thử. Các tham số lần lượt là giới hạn tọa độ ban đầu \(b\), số mỏ khoáng sản \(k\) và số đợt thăm dò tối đa \(w\). Các vị trí mỏ khoáng sản đôi một khác nhau và đã được cố định trước khi gọi hàm.
Trong khi thực hiện find_deposits, bạn có thể gọi hàm do bộ chấm cung cấp:
std::vector<long long> probe(const std::vector<std::pair<long long, long long>>& points);
Mỗi lần gọi probe(points) gửi một đợt gồm \(d=\texttt{points.size()}\) thiết bị. Mỗi phần tử của points là một cặp tọa độ \((s_j,t_j)\), trong đó first là hoành độ và second là tung độ. Tọa độ và khoảng cách dùng kiểu long long (số nguyên có dấu 64 bit).
probe nhiều nhất \(w\) lần. Tổng số thiết bị trong tất cả các lần gọi không được vượt quá \(2\cdot 10^4\).Hàm probe trả về một std::vector<long long> gồm đúng \(k\cdot d\) khoảng cách Manhattan, sắp xếp theo thứ tự không giảm. Các khoảng cách trùng nhau vẫn xuất hiện đủ số lần; không có thông tin cho biết khoảng cách nào thuộc về thiết bị hay mỏ nào.
Để kết thúc, find_deposits phải trả về một std::vector<std::pair<long long, long long>> gồm đúng \(k\) vị trí mỏ khoáng sản, mỗi vị trí xuất hiện đúng một lần, theo thứ tự bất kỳ. Trả về đáp án không tính là một đợt thăm dò. Không bắt buộc phải gọi probe nếu bạn đã xác định được đáp án đúng.
Không cài đặt main, không đọc stdin, không ghi stdout và không chèn mã nguồn bộ chấm vào bài nộp. Chỉ gọi probe trong lúc find_deposits đang chạy. Một lời gọi không hợp lệ (kể cả đợt thứ \(w+1\)) làm bộ chấm kết thúc chương trình ngay lập tức và bộ kiểm thử nhận \(0\) điểm; lời gọi đó không trả về giá trị báo lỗi và không ném ngoại lệ để bạn bắt. Nếu hàm trả về sai số lượng hoặc sai vị trí, bộ kiểm thử cũng nhận \(0\) điểm. Sau khi hàm trả về, bộ chấm kiểm tra đáp án rồi kết thúc chương trình; bạn không cần gọi hàm kết thúc nào khác.
Các bộ kiểm thử được chia thành các nhóm, mỗi nhóm có một số điểm. Để nhận được điểm của một nhóm, chương trình phải giải đúng tất cả các bộ kiểm thử trong nhóm đó. Điểm cuối cùng là điểm cao nhất của một lần nộp bài.
Bản ghi dưới đây giữ nguyên các tham số, hai đợt thăm dò, các khoảng cách và đáp án của ví dụ. Bộ chấm gọi: chỉ lời gọi hàm của bạn; Bạn gọi: chỉ lời gọi probe; Bộ chấm trả về: chỉ kết quả của lời gọi đó; Bạn trả về: chỉ giá trị trả về cuối cùng của find_deposits. Dấu ngoặc nhọn biểu diễn các vector và cặp tọa độ theo cú pháp C++; các nhãn chỉ để minh họa, không phải dữ liệu cần đọc hoặc in.
Ví dụ gọi hàm 1
Bộ chấm gọi: find_deposits(4, 2, 10)
Bạn gọi: probe({{-4, -3}, {-1, 0}, {2, -1}})
Bộ chấm trả về: {2, 4, 4, 4, 6, 10}
Bạn gọi: probe({{1, 2}, {0, -2}})
Bộ chấm trả về: {0, 3, 5, 8}
Bạn trả về: {{1, 2}, {-3, -2}}
Trong ví dụ này, có \(k=2\) mỏ khoáng sản tại các vị trí \((1,2)\) và \((-3,-2)\), được biểu diễn bằng các ngôi sao màu đỏ.
Trong đợt đầu tiên, bạn có thể gửi \(d=3\) thiết bị đến \((-4,-3)\), \((-1,0)\) và \((2,-1)\), được biểu diễn bằng các chấm màu đen. Đợt này trả về \(6\) khoảng cách: \(2,4,4,4,6,10\).
Trong đợt tiếp theo, bạn có thể gửi \(d=2\) thiết bị đến \((1,2)\) và \((0,-2)\). Đợt này trả về \(4\) khoảng cách: \(0,3,5,8\).
Một dãy số nguyên dương \((x_1,\ldots,x_m)\) được gọi là tốt nếu \(x_1=1\) và với mỗi \(1<j\le m\), ta có \(x_j=x_{j-1}+1\) hoặc \(x_j=x_k\cdot x_l\) với một cặp chỉ số \(k,l\) nào đó thỏa mãn \(0<k\le l<j\).
Chẳng hạn, cả hai dãy \((1,1)\) và \((1,2)\) đều tốt, nhưng dãy \((1,3)\) không tốt.
Cho \(n\) số nguyên \(w_1,\ldots,w_n\). Trọng số của một dãy số nguyên \((x_1,\ldots,x_m)\) thỏa mãn \(1\le x_j\le n\) với mọi \(1\le j\le m\) được định nghĩa là
Chẳng hạn, với các trọng số \(w_1=10\), \(w_2=42\), \(w_3=1\), trọng số của dãy \((1,1)\) là \(20\) và trọng số của dãy \((1,3)\) là \(11\).
Với \(1\le v\le n\), gọi \(s_v\) là trọng số nhỏ nhất có thể của một dãy tốt chứa giá trị \(v\).
Nhiệm vụ của bạn là xác định các giá trị \(s_1,\ldots,s_n\).
Dòng đầu tiên chứa số nguyên \(n\), là số lượng trọng số.
\(n\) dòng tiếp theo lần lượt chứa các trọng số nguyên \(w_1,\ldots,w_n\), mỗi dòng một số.
In \(n\) dòng lần lượt chứa \(s_1,\ldots,s_n\).
Các bộ kiểm thử được chia thành các nhóm, mỗi nhóm có một số điểm. Để nhận được điểm của một nhóm, chương trình phải giải đúng tất cả các bộ kiểm thử trong nhóm đó. Điểm cuối cùng là điểm cao nhất của một lần nộp bài.
Ví dụ 1
3
10
42
1
10
52
53