| # | Bài tập | Điểm | Thời gian: | Giới hạn bộ nhớ |
|---|---|---|---|---|
| 1 | IOI 2020 - Comparing Plants | 100 (p) | 4.0s | 2G |
| 2 | IOI 2020 - Connecting Supertrees | 100 (p) | 1.0s | 2G |
| 3 | IOI 2020 - Carnival Tickets | 100 (p) | 2.0s | 2G |
Nhà thực vật học Hazel đến tham quan một triển lãm đặc biệt tại Vườn Bách thảo Singapore. Trong triển lãm, \(n\) cây có chiều cao đôi một khác nhau được đặt trên một vòng tròn. Các cây được gán nhãn từ \(0\) đến \(n-1\) theo chiều kim đồng hồ, với cây \(n-1\) nằm bên cạnh cây \(0\).
Với mỗi cây \(i\) (\(0 \le i \le n-1\)), Hazel so sánh cây \(i\) với từng cây trong \(k-1\) cây kế tiếp theo chiều kim đồng hồ, rồi ghi lại số \(r[i]\) là số cây cao hơn cây \(i\) trong số \(k-1\) cây đó. Như vậy, mỗi giá trị \(r[i]\) phụ thuộc vào tương quan chiều cao của một số cây liên tiếp.
Ví dụ, giả sử \(n=5\), \(k=3\) và \(i=3\). Khi đó, \(k-1=2\) cây kế tiếp theo chiều kim đồng hồ tính từ cây \(i=3\) là cây \(4\) và cây \(0\). Nếu cây \(4\) cao hơn cây \(3\) và cây \(0\) thấp hơn cây \(3\), Hazel sẽ ghi lại \(r[3]=1\).
Bạn có thể giả sử Hazel đã ghi các giá trị \(r[i]\) chính xác. Do đó, tồn tại ít nhất một cách gán các chiều cao đôi một khác nhau cho các cây phù hợp với những giá trị này.
Bạn được yêu cầu so sánh chiều cao của \(q\) cặp cây. Đáng tiếc, bạn không thể đến triển lãm. Nguồn thông tin duy nhất của bạn là sổ ghi chép của Hazel, chứa giá trị \(k\) và dãy \(r[0],\ldots,r[n-1]\).
Với mỗi cặp cây khác nhau \(x\) và \(y\) cần so sánh, hãy xác định trường hợp nào trong ba trường hợp sau xảy ra:
Bạn cần cài đặt các hàm C++ sau:
void init(int k, std::vector<int> r);
compare_plants.int compare_plants(int x, int y);
Trình chấm mẫu đọc dữ liệu theo định dạng sau:
n k q.r[0] r[1] ... r[n-1].x y cho lời gọi compare_plants thứ \(i\) (đánh số từ \(0\)).Trình chấm mẫu in trên dòng \(1+i\) (\(0 \le i \le q-1\)) giá trị trả về của lời gọi compare_plants thứ \(i\).
Tồn tại ít nhất một cách gán các chiều cao đôi một khác nhau cho các cây phù hợp với mảng \(r\).
| Nhóm | Điểm | Ràng buộc bổ sung |
|---|---|---|
| 1 | 5 | \(k=2\). |
| 2 | 14 | \(n \le 5000\) và \(2\cdot k>n\). |
| 3 | 13 | \(2\cdot k>n\). |
| 4 | 17 | Đáp án đúng của mỗi lời gọi compare_plants là \(1\) hoặc \(-1\). |
| 5 | 11 | \(n \le 300\) và \(q \le \frac{n\cdot(n-1)}{2}\). |
| 6 | 15 | \(x=0\) trong mỗi lời gọi compare_plants. |
| 7 | 25 | Không có ràng buộc bổ sung. |
Ví dụ 1
init(3, [0, 1, 1, 2])
Giả sử trình chấm gọi compare_plants(0, 2). Vì \(r[0]=0\), ta suy ra ngay cây \(2\) không cao hơn cây \(0\). Do đó, lời gọi phải trả về \(1\).
Giả sử tiếp theo trình chấm gọi compare_plants(1, 2). Trong mọi cách gán chiều cao phù hợp với các ràng buộc trên, cây \(1\) thấp hơn cây \(2\). Do đó, lời gọi phải trả về \(-1\).
Ví dụ 2
init(2, [0, 1, 0, 1])
Giả sử trình chấm gọi compare_plants(0, 3). Vì \(r[3]=1\), ta biết cây \(0\) cao hơn cây \(3\). Do đó, lời gọi phải trả về \(1\).
Giả sử tiếp theo trình chấm gọi compare_plants(1, 3). Hai cách gán chiều cao \([3,1,4,2]\) và \([3,2,4,1]\) đều phù hợp với các phép đo của Hazel. Cây \(1\) thấp hơn cây \(3\) trong một cách gán và cao hơn cây \(3\) trong cách gán còn lại, nên lời gọi phải trả về \(0\).
IOI 2020, Ngày 1 — Comparing Plants (plants). Đề chính thức tiếng Anh và bản dịch tiếng Việt.
Gardens by the Bay là một công viên thiên nhiên rộng lớn ở Singapore. Trong công viên có \(n\) tòa tháp, được gọi là siêu cây (supertree). Các tháp được gán nhãn từ \(0\) đến \(n-1\). Ta muốn xây dựng một tập gồm không hoặc nhiều cầu. Mỗi cầu nối hai tháp khác nhau và có thể đi qua theo cả hai chiều. Không được có hai cầu nối cùng một cặp tháp.
Một đường đi từ tháp \(x\) đến tháp \(y\) là một dãy gồm một hoặc nhiều tháp sao cho:
Lưu ý rằng theo định nghĩa, có đúng một đường đi từ một tháp đến chính nó; số đường đi khác nhau từ tháp \(i\) đến tháp \(j\) bằng số đường đi khác nhau từ tháp \(j\) đến tháp \(i\).
Kiến trúc sư chính phụ trách thiết kế muốn các cầu được xây dựng sao cho với mọi \(0 \le i,j \le n-1\), có đúng \(p[i][j]\) đường đi khác nhau từ tháp \(i\) đến tháp \(j\), trong đó \(0 \le p[i][j] \le 3\).
Hãy xây dựng một tập các cầu thỏa mãn yêu cầu của kiến trúc sư, hoặc xác định rằng không thể thực hiện được.
Bạn cần cài đặt hàm C++ sau:
int construct(std::vector<std::vector<int>> p);
build (mô tả bên dưới) đúng một lần để báo cáo phương án xây dựng, rồi trả về \(1\).build lần nào.construct được gọi đúng một lần.Hàm build được định nghĩa như sau:
void build(std::vector<std::vector<int>> b);
Trình chấm mẫu đọc dữ liệu theo định dạng sau:
n.p[i][0] p[i][1] ... p[i][n-1].Trình chấm mẫu in:
construct.Nếu giá trị trả về của construct là \(1\), trình chấm mẫu in thêm:
b[i][0] b[i][1] ... b[i][n-1].| Nhóm | Điểm | Ràng buộc bổ sung |
|---|---|---|
| 1 | 11 | \(p[i][j]=1\) với mọi \(0 \le i,j \le n-1\). |
| 2 | 10 | \(p[i][j]=0\) hoặc \(1\) với mọi \(0 \le i,j \le n-1\). |
| 3 | 19 | \(p[i][j]=0\) hoặc \(2\) với mọi \(i\ne j\), \(0 \le i,j \le n-1\). |
| 4 | 35 | \(0 \le p[i][j] \le 2\) với mọi \(0 \le i,j \le n-1\), và tồn tại ít nhất một phương án xây dựng thỏa mãn yêu cầu. |
| 5 | 21 | \(0 \le p[i][j] \le 2\) với mọi \(0 \le i,j \le n-1\). |
| 6 | 4 | Không có ràng buộc bổ sung. |
Ví dụ 1
construct([[1, 1, 2, 2], [1, 1, 2, 2], [2, 2, 1, 2], [2, 2, 2, 1]])
Điều này có nghĩa là phải có đúng một đường đi từ tháp \(0\) đến tháp \(1\). Với mọi cặp tháp khác \((x,y)\) thỏa mãn \(0 \le x<y \le 3\), phải có đúng hai đường đi từ tháp \(x\) đến tháp \(y\). Có thể đạt được điều này bằng \(4\) cầu nối các cặp tháp \((0,1)\), \((1,2)\), \((1,3)\) và \((2,3)\).
Để báo cáo phương án này, hàm construct phải thực hiện lời gọi sau:
build([[0, 1, 0, 0], [1, 0, 1, 1], [0, 1, 0, 1], [0, 1, 1, 0]])
Sau đó, hàm phải trả về \(1\).
Trong trường hợp này, có nhiều phương án xây dựng thỏa mãn yêu cầu; tất cả đều được coi là đúng.
Ví dụ 2
construct([[1, 0], [0, 1]])
Điều này có nghĩa là không được có đường đi giữa hai tháp. Yêu cầu này chỉ có thể được thỏa mãn khi không có cầu nào.
Vì vậy, hàm construct phải thực hiện lời gọi sau:
build([[0, 0], [0, 0]])
Sau đó, hàm construct phải trả về \(1\).
Ví dụ 3
construct([[1, 3], [3, 1]])
Điều này có nghĩa là phải có đúng \(3\) đường đi từ tháp \(0\) đến tháp \(1\). Không thể thỏa mãn tập yêu cầu này. Vì vậy, hàm construct phải trả về \(0\) mà không gọi build lần nào.
IOI 2020, Ngày 1 — Connecting Supertrees (supertrees). Đề chính thức tiếng Anh và bản dịch tiếng Việt.
Ringo đang tham dự một lễ hội ở Singapore. Cậu có một số vé dự thưởng trong túi và muốn sử dụng chúng tại quầy trò chơi có thưởng. Mỗi vé thuộc một trong \(n\) màu và có in một số nguyên không âm. Các số nguyên in trên những vé khác nhau có thể bằng nhau. Theo một luật lệ kỳ quặc của lễ hội, \(n\) được bảo đảm là số chẵn.
Ringo có \(m\) vé mỗi màu trong túi, tổng cộng \(n\cdot m\) vé. Vé \(j\) của màu \(i\) có in số nguyên \(x[i][j]\) (\(0 \le i \le n-1\) và \(0 \le j \le m-1\)).
Trò chơi diễn ra trong \(k\) vòng, đánh số từ \(0\) đến \(k-1\). Mỗi vòng diễn ra theo thứ tự sau:
Các vé còn lại trong túi Ringo sau \(k\) vòng chơi cũng bị bỏ đi.
Quan sát kỹ, Ringo nhận ra trò chơi đã bị gian lận! Thực ra có một máy in bên trong hộp bốc thăm may mắn. Trong mỗi vòng, người quản trò tìm một số nguyên \(b\) làm cho giá trị phần thưởng của vòng đó nhỏ nhất. Giá trị được chọn được in lên thẻ đặc biệt của vòng đó.
Biết tất cả những thông tin này, Ringo muốn phân bổ vé cho các vòng chơi. Cụ thể, cậu muốn chọn tập vé sử dụng trong mỗi vòng để tổng giá trị các phần thưởng là lớn nhất.
Bạn cần cài đặt hàm C++ sau:
long long find_maximum(int k, std::vector<std::vector<int>> x);
allocate_tickets (mô tả bên dưới) đúng một lần, mô tả \(k\) tập vé, mỗi tập cho một vòng. Cách phân bổ phải làm tổng giá trị các phần thưởng lớn nhất.Hàm allocate_tickets được định nghĩa như sau:
void allocate_tickets(std::vector<std::vector<int>> s);
Trình chấm mẫu đọc dữ liệu theo định dạng sau:
n m k.x[i][0] x[i][1] ... x[i][m-1].Trình chấm mẫu in câu trả lời theo định dạng sau:
find_maximum.s[i][0] s[i][1] ... s[i][m-1].| Nhóm | Điểm | Ràng buộc bổ sung |
|---|---|---|
| 1 | 11 | \(m=1\). |
| 2 | 16 | \(k=1\). |
| 3 | 14 | \(0 \le x[i][j] \le 1\) với mọi \(0 \le i \le n-1\) và \(0 \le j \le m-1\). |
| 4 | 14 | \(k=m\). |
| 5 | 12 | \(n,m \le 80\). |
| 6 | 23 | \(n,m \le 300\). |
| 7 | 10 | Không có ràng buộc bổ sung. |
Ví dụ 1
find_maximum(2, [[0, 2, 5], [1, 1, 3]])
Điều này có nghĩa là:
Một cách phân bổ đạt tổng giá trị phần thưởng lớn nhất là:
- Ở vòng $1$, Ringo chọn vé $2$ của màu $0$ (in số $5$) và vé $1$ của màu $1$ (in số $1$). Giá trị phần thưởng nhỏ nhất có thể trong vòng này là $4$. Ví dụ, người quản trò có thể chọn $b=3$:
- Vì vậy, tổng giá trị phần thưởng là:
Để báo cáo cách phân bổ này, hàm `find_maximum` phải thực hiện lời gọi `allocate_tickets` sau:
```text
allocate_tickets([[0, -1, 1], [-1, 1, 0]])
```
Cuối cùng, hàm `find_maximum` phải trả về $7$.
Ví dụ 2
find_maximum(1, [[5, 9], [1, 4], [3, 6], [2, 7]])
Điều này có nghĩa là:
Một cách phân bổ đạt tổng giá trị phần thưởng lớn nhất là:
Để báo cáo phương án này, hàm `find_maximum` phải thực hiện lời gọi `allocate_tickets` sau:
```text
allocate_tickets([[-1, 0], [0, -1], [0, -1], [-1, 0]])
```
Cuối cùng, hàm `find_maximum` phải trả về $12$.
IOI 2020, Ngày 1 — Carnival Tickets (tickets). Đề chính thức tiếng Anh và bản dịch tiếng Việt.