| # | Bài tập | Điểm | Thời gian: | Giới hạn bộ nhớ |
|---|---|---|---|---|
| 1 | JOI 2014 - Constellation 2 | 100 (p) | 5.0s | 256M |
| 2 | JOI 2014 - Kanji Shiritori | 100 (p) | 1.0s | 256M |
| 3 | JOI 2014 - Straps | 100 (p) | 1.0s | 256M |
JOI và IOI là đôi bạn thân. Một ngày nọ, hai bạn quyết định đến đài quan sát trên đỉnh núi để ngắm sao.
Từ đài quan sát có thể nhìn thấy \(N\) ngôi sao, được đánh số từ \(1\) đến \(N\). Mỗi ngôi sao có một trong ba màu: đỏ, xanh lam hoặc vàng.
Các ngôi sao được quan sát từ đây được biểu diễn bằng các điểm trên mặt phẳng tọa độ. Ngôi sao \(i\) (\(1 \le i \le N\)) tương ứng với điểm \(P_i(X_i,Y_i)\). Các điểm \(P_1,\ldots,P_N\) đôi một phân biệt và không có ba điểm nào thẳng hàng.
JOI và IOI quyết định tạo ra một chòm sao mang tên JOIOI. Trước tiên, hai bạn nghĩ đến việc dùng các tam giác nối ba ngôi sao, mỗi màu đỏ, xanh lam và vàng đúng một ngôi sao. Gọi một tam giác như vậy là tam giác tốt.
Hai bạn coi một cặp tam giác tốt không xét thứ tự là một phương án cho chòm sao JOIOI nếu thỏa mãn điều kiện sau:
Hình bên trái thỏa mãn điều kiện. Hai hình bên phải không thỏa mãn điều kiện.
JOI và IOI muốn đếm có bao nhiêu phương án cho chòm sao JOIOI. Lưu ý rằng ngay cả khi cùng sử dụng sáu ngôi sao, nếu cách nối chúng thành hai tam giác tốt khác nhau thì vẫn được tính là những phương án khác nhau.
Cho thông tin về các ngôi sao được quan sát từ đài quan sát, hãy viết chương trình tính tổng số phương án cho chòm sao JOIOI.
Đọc dữ liệu từ đầu vào chuẩn theo định dạng sau:
In ra đầu ra chuẩn một dòng chứa một số nguyên là tổng số phương án cho chòm sao JOIOI.
Mọi dữ liệu vào đều thỏa mãn:
Ví dụ 1
7
0 0 0
2 0 1
1 2 2
-2 1 0
-2 -3 0
0 -2 1
2 -2 2
4
Ví dụ 2
8
16 0 0
17 0 0
0 7 2
0 -7 2
-1 -1 1
-1 1 2
-6 4 1
-6 -4 1
12
Ví dụ 3
21
1 20 0
4 20 0
0 22 0
5 22 0
6 25 0
8 25 0
4 26 0
11 11 1
7 12 1
14 13 1
8 15 1
15 16 1
11 17 1
18 0 2
13 2 2
16 2 2
19 4 2
18 6 2
21 8 2
24 8 2
19 10 2
7748
Anna và Bruno sắp làm bài kiểm tra chữ Hán ở trường. Hai bạn biết \(N\) chữ Hán, được đánh số từ \(0\) đến \(N-1\), và \(M\) từ, được đánh số từ \(0\) đến \(M-1\). Các từ đều được tạo thành từ những chữ Hán mà hai bạn biết. Từ \(i\) có chữ đầu tiên là chữ Hán \(A_i\) và chữ cuối cùng là chữ Hán \(B_i\). Với mọi từ, \(A_i \ne B_i\). Các cặp \((A_i,B_i)\) đôi một khác nhau, nghĩa là nếu \(i \ne j\) thì \((A_i,B_i) \ne (A_j,B_j)\). Mỗi từ còn có một thời gian viết \(C_i\) xác định.
Bài kiểm tra gồm \(Q\) câu hỏi có dạng sau:
Câu hỏi \(j\): Hãy đưa ra một chuỗi nối từ bằng chữ Hán bắt đầu bằng chữ Hán \(S_j\) và kết thúc bằng chữ Hán \(T_j\).
Với mọi câu hỏi, \(S_j \ne T_j\). Các cặp \((S_j,T_j)\) cũng đôi một khác nhau, nghĩa là nếu \(i \ne j\) thì \((S_i,T_i) \ne (S_j,T_j)\).
Một chuỗi nối từ bằng chữ Hán là một dãy từ trong đó chữ cuối của mỗi từ trùng với chữ đầu của từ ngay sau nó, như trong Hình 1. Chuỗi bắt đầu bằng chữ Hán \(S_j\) và kết thúc bằng chữ Hán \(T_j\) có chữ đầu của từ đầu tiên là \(S_j\), và chữ cuối của từ cuối cùng là \(T_j\).
Hình 1: Một chuỗi nối từ bằng chữ Hán bắt đầu bằng \(S_j = \text{「報」}\) và kết thúc bằng \(T_j = \text{「情」}\).
Có thể có nhiều chuỗi trả lời được một câu hỏi. Tuy nhiên, vì thời gian làm bài ngắn, hai bạn phải đưa ra một chuỗi có tổng thời gian viết nhỏ nhất. Nếu có nhiều chuỗi cùng đạt thời gian nhỏ nhất thì có thể chọn bất kỳ chuỗi nào trong số đó. Thời gian viết một chuỗi là tổng thời gian viết của tất cả các từ trong chuỗi.
Ngay trước giờ kiểm tra, Bruno quên mất thời gian viết \(C_{U_0},C_{U_1},\ldots,C_{U_{K-1}}\) của các từ \(U_0,U_1,\ldots,U_{K-1}\). Tình cờ, cả \(K\) từ này đều có cùng chữ đầu tiên. Bruno đã báo cho Anna biết việc này, nhưng không còn đủ thời gian trước khi bài kiểm tra bắt đầu, nên Anna quyết định truyền thông tin cho Bruno trong lúc làm bài. Anna có thể gõ lên bàn để gửi cho Bruno một giá trị \(0\) hoặc \(1\) mỗi lần. Anna muốn số lần gửi ít nhất có thể.
Liệu Bruno có thể đạt điểm tối đa trong bài kiểm tra hay không?
Cả Anna và Bruno đều được cung cấp số chữ Hán \(N\); số từ \(M\) cùng chữ đầu và chữ cuối của mỗi từ; số câu hỏi \(Q\) cùng thông tin của từng câu hỏi; số từ \(K\) mà Bruno quên thời gian viết cùng số hiệu của các từ đó. Ngoài ra, Anna được cung cấp thời gian viết của cả \(M\) từ, còn Bruno chỉ được cung cấp thời gian viết của \(M-K\) từ mà cậu không quên.
Hãy viết chương trình để Anna truyền thông tin cho Bruno và Bruno trả lời đúng mọi câu hỏi trong bài kiểm tra.
Bạn phải nộp hai tệp viết bằng cùng một ngôn ngữ lập trình.
Tệp thứ nhất có tên Anna.c hoặc Anna.cpp, cài đặt chiến lược của Anna. Tệp này phải cài đặt hàm sau:
void Anna(int N, int M, int A[], int B[], long long C[],
int Q, int S[], int T[], int K, int U[]);
Hàm này được gọi đúng một lần, ở đầu quá trình thực hiện.
| Tham số | Ý nghĩa |
|---|---|
N |
Số chữ Hán \(N\). |
M |
Số từ \(M\). |
A |
Mảng độ dài \(M\); A[i] là số hiệu \(A_i\) của chữ đầu tiên của từ \(i\). |
B |
Mảng độ dài \(M\); B[i] là số hiệu \(B_i\) của chữ cuối cùng của từ \(i\). |
C |
Mảng độ dài \(M\); C[i] là thời gian \(C_i\) để viết từ \(i\). |
Q |
Số câu hỏi \(Q\). |
S |
Mảng độ dài \(Q\); S[j] là số hiệu \(S_j\) của chữ đầu tiên trong đáp án cho câu hỏi \(j\). |
T |
Mảng độ dài \(Q\); T[j] là số hiệu \(T_j\) của chữ cuối cùng trong đáp án cho câu hỏi \(j\). |
K |
Số từ \(K\) mà Bruno quên thời gian viết. |
U |
Mảng độ dài \(K\); U[0], U[1], …, U[K-1] là số hiệu \(U_0,U_1,\ldots,U_{K-1}\) của những từ mà Bruno quên thời gian viết. |
Trong chương trình của Anna, bạn có thể gọi hàm sau để gửi một giá trị \(0\) hoặc \(1\) cho Bruno:
void Tap(int x);
Tham số x là giá trị gửi cho Bruno. Hàm này được khai báo trong Annalib.h.
x phải bằng \(0\) hoặc \(1\). Nếu không, kết quả là Wrong Answer [1].Tap vượt quá \(1\,000\), kết quả là Wrong Answer [2].Nếu một lời gọi Tap bị kết luận là sai, chương trình sẽ bị kết thúc ngay tại thời điểm đó.
Tệp thứ hai có tên Bruno.c hoặc Bruno.cpp, cài đặt chiến lược của Bruno. Tệp này phải cài đặt hàm sau:
void Bruno(int N, int M, int A[], int B[], long long C[],
int Q, int S[], int T[], int K, int U[], int L, int X[]);
Hàm này được gọi đúng một lần, sau khi hàm Anna đã được gọi.
N, M, A, B, Q, S, T, K, U giống như khi gọi Anna.C là mảng chứa thời gian viết của \(M\) từ. Với \(0 \le i < M\), C[i] là thời gian \(C_i\) để viết từ \(i\), nhưng bằng \(-1\) nếu \(i\) là một trong các số hiệu \(U_0,U_1,\ldots,U_{K-1}\).L là số giá trị \(0\) hoặc \(1\) mà Anna đã gửi.X là mảng độ dài \(L\), cho biết Anna đã gửi các giá trị theo thứ tự X[0], X[1], …, X[L-1].Trong chương trình của Bruno, bạn có thể gọi hàm sau, được khai báo trong Brunolib.h:
void Answer(int w);
w phải là một số nguyên từ \(0\) đến \(M-1\), hoặc bằng \(-1\). Nếu không, kết quả là Wrong Answer [3].Answer(-1) đủ \(Q\) lần, kết quả là Wrong Answer [4].Nếu một lời gọi Answer bị kết luận là sai, chương trình sẽ bị kết thúc ngay tại thời điểm đó.
Chương trình phải sử dụng hàm này để lần lượt trả lời đủ \(Q\) câu hỏi. Ở lần trả lời thứ \(j+1\) (\(0 \le j \le Q-1\)), thực hiện các bước sau:
Answer(w) với w là số hiệu từng từ, theo thứ tự từ đầu dãy đến cuối dãy.Answer(-1) để kết thúc đáp án của câu hỏi này.Sau khi hàm Bruno thực hiện xong, các đáp án được kiểm tra như sau:
Answer(-1) nhỏ hơn \(Q\), kết quả là Wrong Answer [5].Bạn được phép cài đặt thêm các hàm nội bộ và khai báo biến toàn cục. Tuy nhiên, hai tệp nộp sẽ được liên kết cùng chương trình chấm thành một tệp thực thi, nên tất cả các biến toàn cục và hàm nội bộ trong mỗi tệp phải được khai báo static để tránh xung đột với các tệp khác.
Khi chấm chính thức, chương trình được chạy thành hai tiến trình, một cho phía Anna và một cho phía Bruno. Vì vậy, Anna và Bruno không thể chia sẻ các biến toàn cục trong chương trình.
Chương trình nộp của bạn không được tương tác với đầu vào chuẩn, đầu ra chuẩn hay bất kỳ tệp nào khác bằng bất kỳ cách nào.
Archive tải từ trang cuộc thi có chứa chương trình chấm mẫu để kiểm thử chương trình của bạn, cùng các tệp mẫu tương ứng với những tệp phải nộp. Chương trình chấm mẫu gồm một tệp grader.c hoặc grader.cpp.
Để kiểm thử chương trình C, chạy lệnh:
gcc -O2 -lm grader.c Anna.c Bruno.c -o grader
Để kiểm thử chương trình C++, chạy lệnh:
g++ -O2 grader.cpp Anna.cpp Bruno.cpp -o grader
Nếu biên dịch thành công, tệp thực thi grader sẽ được tạo ra.
Chương trình chấm chính thức khác với chương trình chấm mẫu. Chương trình chấm mẫu chỉ chạy trong một tiến trình, đọc dữ liệu từ đầu vào chuẩn và ghi kết quả ra đầu ra chuẩn.
Chương trình chấm mẫu đọc dữ liệu từ đầu vào chuẩn theo định dạng sau:
Khi việc thực hiện chương trình kết thúc bình thường, chương trình chấm mẫu in một dòng ra đầu ra chuẩn theo một trong các dạng sau; dấu ngoặc kép không được in ra:
Tap, chẳng hạn Accepted : L = 100.Wrong Answer [1].Mọi dữ liệu vào đều thỏa mãn:
Nhóm 1 — 10 điểm
\(Q \le 10\).
Anna được gọi Tap nhiều nhất \(1\,000\) lần.
Nhóm 2 — 22 điểm
Anna được gọi Tap nhiều nhất \(180\) lần.
Nhóm 3 — 8 điểm
Anna được gọi Tap nhiều nhất \(160\) lần.
Nhóm 4 — 40 điểm
Anna được gọi Tap nhiều nhất \(90\) lần.
Nhóm 5 — 20 điểm
Gọi \(L\) là số lần gọi Tap lớn nhất trong tất cả các test của subtask này. Điểm của subtask được tính như sau:
Ở đây, \(\lfloor x \rfloor\) là số nguyên lớn nhất không vượt quá \(x\).
Dưới đây là một ví dụ dữ liệu vào của chương trình chấm mẫu và một trình tự gọi hàm tương ứng.
4 5 3 2
2 1 10
0 2 20
3 1 30
0 1 40
3 0 50
3 0 50
3 1 30
0 1 30
1
3
Các lời gọi trong bảng được thực hiện theo thứ tự từ trên xuống dưới.
| Phía Anna | Phía Bruno |
|---|---|
Anna(...) |
|
Tap(0) |
|
Tap(0) |
|
Tap(1) |
|
Tap(0) |
|
Bruno(...) |
|
Answer(4) |
|
Answer(-1) |
|
Answer(2) |
|
Answer(-1) |
|
Answer(1) |
|
Answer(0) |
|
Answer(-1) |
Các lời gọi Tap trong ví dụ này không nhất thiết mang thông tin có ý nghĩa. Các tham số được truyền cho Anna(...) và Bruno(...) như sau:
| Tham số | Anna(...) |
Bruno(...) |
|---|---|---|
N |
4 |
4 |
M |
5 |
5 |
A |
{2, 0, 3, 0, 3} |
{2, 0, 3, 0, 3} |
B |
{1, 2, 1, 1, 0} |
{1, 2, 1, 1, 0} |
C |
{10, 20, 30, 40, 50} |
{10, -1, 30, -1, 50} |
Q |
3 |
3 |
S |
{3, 3, 0} |
{3, 3, 0} |
T |
{0, 1, 1} |
{0, 1, 1} |
K |
2 |
2 |
U |
{1, 3} |
{1, 3} |
L |
— | 4 |
X |
— | {0, 0, 1, 0} |
Hãy chú ý đến hai phần tử C[1] và C[3] của mảng C.
JOI có \(N\) dây treo trang trí để gắn vào điện thoại di động, được đánh số từ \(1\) đến \(N\). Cậu muốn chọn một số dây treo trong số đó để gắn vào điện thoại.
Những dây treo của JOI hơi đặc biệt: một số dây có các đầu nối để gắn thêm những dây treo khác. Mỗi dây treo có thể được gắn trực tiếp vào điện thoại hoặc vào một đầu nối của một dây treo khác. Mỗi đầu nối gắn được một dây treo. Có thể gắn trực tiếp vào điện thoại nhiều nhất một dây treo.
Mỗi dây treo mang lại một mức độ vui thích nhất định khi được gắn vào, được biểu diễn bằng một số nguyên. Có những dây treo mà JOI không thích; mức độ vui thích của chúng là số âm.
JOI muốn tổng mức độ vui thích của các dây treo được nối với điện thoại là lớn nhất. Không nhất thiết phải gắn dây treo vào mọi đầu nối, và cũng có thể không gắn dây treo nào.
Cho thông tin về \(N\) dây treo của JOI, hãy viết chương trình tìm tổng mức độ vui thích lớn nhất của các dây treo được nối với điện thoại khi chọn cách gắn phù hợp.
Đọc dữ liệu từ đầu vào chuẩn theo định dạng sau:
In ra đầu ra chuẩn một dòng chứa một số nguyên là tổng mức độ vui thích lớn nhất của các dây treo được nối với điện thoại.
Mọi dữ liệu vào đều thỏa mãn:
Ví dụ 1
5
0 4
2 -2
1 -1
0 1
0 3
5
Với dữ liệu này, cách gắn dưới đây cho tổng mức độ vui thích bằng \(5\), là giá trị lớn nhất:
Ví dụ 2
6
2 -3
3 -1
0 -4
0 -2
1 -3
4 -1
0
Trong ví dụ này, mọi dây treo đều có mức độ vui thích nhỏ hơn \(0\). Vì vậy, tổng mức độ vui thích lớn nhất đạt được khi không gắn dây treo nào.
Ví dụ 3
15
1 -4034
1 3406
0 6062
4 -6824
0 9798
0 4500
0 -1915
1 2137
0 9786
0 7330
0 -9365
2 2730
0 -5797
0 6129
0 8925
43417