| # | Bài tập | Điểm | Thời gian: | Giới hạn bộ nhớ |
|---|---|---|---|---|
| 1 | BOI 2014 - Cop and Robber | 100 (p) | 1.5s | 256M |
| 2 | BOI 2014 - Three Friends | 100 (p) | 0.5s | 256M |
| 3 | BOI 2014 - Sequence | 100 (p) | 1.0s | 256M |
Tình hình tội phạm ở thành phố Bytemore đang trở nên nghiêm trọng. Những vụ cướp xảy ra hằng ngày, và một cảnh sát tuần tra phải đuổi theo tên cướp qua các con hẻm nối những góc phố. Vì thuộc đường hơn cảnh sát, những tên cướp thường trốn thoát. Sở cảnh sát đã lập bản đồ thành phố và muốn dùng máy tính để tìm chiến lược truy đuổi.
Cuộc truy đuổi giữa một cảnh sát và một tên cướp được mô hình hóa như sau:
Cho bản đồ thành phố, hãy xác định liệu cảnh sát có thể bảo đảm bắt được tên cướp hay không. Nếu có, chương trình phải thực hiện các nước đi của cảnh sát để bắt hắn. Luôn giả sử tên cướp chơi tối ưu.
Đây là bài lập trình theo giao diện hàm. Với giao diện C++, nộp tệp mã nguồn có #include "coprobber.h" và cài đặt hai hàm sau; không viết hàm main:
int start(int N, bool A[MAX_N][MAX_N]);
int nextMove(int R);
Hằng MAX_N bằng \(500\).
Hàm start nhận:
A[i][j] bằng true nếu có con hẻm nối \(i\) và \(j\), và bằng false nếu không có.Mọi con hẻm đều đi được theo hai chiều: A[i][j] == A[j][i]. Không có hẻm nối một góc phố với chính nó, nên A[i][i] luôn bằng false. Có thể đi từ một góc phố bất kỳ đến mọi góc phố khác qua các con hẻm.
Nếu có thể bảo đảm bắt được tên cướp, start phải trả về số hiệu góc phố mà cảnh sát chọn làm vị trí ban đầu. Nếu không thể, hàm phải trả về \(-1\).
Hàm nextMove(R) nhận vị trí hiện tại \(R\) của tên cướp và phải trả về góc phố mà cảnh sát đứng sau lượt đi của mình.
start được gọi đúng một lần, trước mọi lần gọi nextMove. Nếu start trả về \(-1\), nextMove không được gọi. Ngược lại, nextMove được gọi nhiều lần cho đến khi một trong các trường hợp sau xảy ra: trả về nước đi không hợp lệ, trạng thái lặp lại, hoặc tên cướp bị bắt.
Gói thử nghiệm kèm theo cung cấp giao diện C++ và một chương trình chấm mẫu được dựng lại từ mô tả này. Chương trình chấm mẫu dùng để thử trên máy cá nhân.
14 điểm: \(2 \le N \le 500\). Mạng lưới có dạng lưới chữ nhật với ít nhất hai hàng và hai cột. Các góc phố được đánh số liên tiếp từ trái sang phải trong mỗi hàng, các hàng từ trên xuống dưới. Cụ thể, với lưới có \(w\) cột, góc ở hàng \(r\), cột \(c\) có số hiệu \(rw+c\) (hàng và cột bắt đầu từ \(0\)); hai góc nối nhau khi kề theo chiều ngang hoặc dọc.
30 điểm: \(2 \le N \le 100\).
Bài làm cần đáp ứng hai yêu cầu: xác định đúng liệu cảnh sát có thể bắt được tên cướp hay không; và nếu có thể thì thực sự bắt được tên cướp bằng các nước đi đã trả về.
Trong phân nhóm 1 và 2, phải đáp ứng cả hai yêu cầu mới được điểm. Trong phân nhóm 3 và 4, nếu chỉ đáp ứng yêu cầu thứ nhất, bài làm được 30% số điểm của phân nhóm. Để chỉ lấy điểm phần xác định, có thể kết thúc bằng cách trả về một nước đi không hợp lệ, chẳng hạn trả về \(-1\) trong nextMove.
Muốn được bất kỳ số điểm nào, chương trình vẫn phải đáp ứng các giới hạn thực thi và không xảy ra lỗi khi chạy.
Ví dụ 1
start(4, [[0, 1, 1, 1], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]) -> 3
nextMove(1) -> 3
nextMove(0) -> 0
Trong lời gọi start, \(0\) và \(1\) lần lượt biểu diễn false và true. Ở đồ thị này, cảnh sát có thể chọn góc phố bất kỳ làm vị trí ban đầu. Nếu bắt đầu ở góc \(0\), cảnh sát có thể đứng yên trong lượt đầu để tên cướp chạy đến đó. Nếu bắt đầu ở một góc khác, cảnh sát có thể chờ tên cướp đến góc \(0\) rồi đi tới bắt hắn.
Chương trình chấm mẫu đọc dữ liệu từ đầu vào chuẩn theo định dạng sau:
Trong bảng chiến lược, chỉ số hàng và cột bắt đầu từ \(0\). Giá trị tại hàng \(c\), cột \(r<N\) là góc phố mà tên cướp đi tới khi đến lượt hắn, cảnh sát ở \(c\) và tên cướp ở \(r\). Các phần tử đường chéo bị bỏ qua vì khi đó tên cướp đã bị bắt. Giá trị cuối cùng trên hàng \(c\) là vị trí ban đầu của tên cướp khi cảnh sát bắt đầu ở \(c\).
Tệp sample1.in mô tả ba góc phố đôi một nối với nhau:
3
0 1 1
1 0 1
1 1 0
1
0 2 1 2
2 0 0 2
1 0 0 1
Tệp sample2.in tương ứng với ví dụ gọi hàm ở trên:
4
0 1 1 1
1 0 0 0
1 0 0 0
1 0 0 0
1
0 0 0 0 1
2 0 0 0 2
3 0 0 0 3
1 0 0 0 1
Với chương trình chấm mẫu kèm theo, kết quả OK biểu thị hoàn thành yêu cầu; PARTFAIL biểu thị xác định đúng khả năng bắt nhưng chưa bắt được tên cướp; FAIL biểu thị không đạt. Điểm phần xác định còn phụ thuộc phân nhóm như đã nêu ở trên. Đây là kết quả của chương trình chấm mẫu; hai hàm bạn cài đặt chỉ cần trả về các giá trị theo giao diện.
Ba người bạn thích chơi trò chơi sau. Người thứ nhất chọn một xâu \(S\). Người thứ hai tạo xâu \(T\) bằng cách ghép hai bản sao của \(S\). Cuối cùng, người thứ ba chèn đúng một chữ cái vào đầu, cuối hoặc một vị trí bất kỳ bên trong \(T\), tạo thành xâu \(U\).
Cho xâu \(U\), hãy khôi phục xâu \(S\) ban đầu.
Dòng đầu chứa số nguyên \(N\), độ dài của xâu \(U\).
Dòng thứ hai chứa xâu \(U\) gồm \(N\) chữ cái tiếng Anh in hoa từ A đến Z.
In ra xâu \(S\) ban đầu. Có hai trường hợp ngoại lệ:
NOT POSSIBLE.NOT UNIQUE.Ví dụ 1
7
ABXCABC
ABC
Ví dụ 2
6
ABCDEF
NOT POSSIBLE
Ví dụ 3
9
ABABABABA
NOT UNIQUE
Adam viết lên bảng một dãy gồm \(K\) số nguyên dương liên tiếp, bắt đầu từ \(N\). Khi Adam rời đi, Billy xóa các chữ số của mỗi số, chỉ giữ lại đúng một chữ số. Như vậy, Billy tạo ra một dãy gồm \(K\) chữ số.
Cho dãy chữ số còn lại trên bảng, hãy tìm giá trị nhỏ nhất của \(N\) có thể là số đầu tiên trong dãy ban đầu.
Dòng đầu chứa số nguyên \(K\), độ dài của dãy.
Dòng thứ hai chứa \(K\) số nguyên \(B_1, B_2, \ldots, B_K\) theo thứ tự trên bảng. Chữ số \(B_i\) phải xuất hiện trong cách viết thập phân của số \(N+i-1\).
In ra một số nguyên: giá trị nhỏ nhất của \(N\) có thể là số đầu tiên trong dãy ban đầu.
Ví dụ 1
6
7 8 9 5 1 2
47
Với \(N=47\), dãy của Adam là \(47,48,49,50,51,52\). Từ mỗi số, Billy có thể giữ lại lần lượt các chữ số \(7,8,9,5,1,2\). Không có giá trị \(N\) nhỏ hơn nào thỏa mãn, nên đáp án là \(47\).