| # | Bài tập | Điểm | Thời gian: | Giới hạn bộ nhớ |
|---|---|---|---|---|
| 1 | IOI 2015 - Horses | 100 (p) | 1.5s | 1G |
| 2 | IOI 2015 - Sorting | 100 (p) | 1.0s | 1G |
| 3 | IOI 2015 - Towns | 100 (p) | 1.0s | 1G |
Mansur thích nuôi ngựa như tổ tiên của mình. Hiện nay anh có đàn ngựa lớn nhất Kazakhstan, nhưng trước đây không phải lúc nào cũng vậy. Cách đây \(N\) năm, Mansur chỉ là một dzhigit (tiếng Kazakhstan nghĩa là chàng trai trẻ) và có đúng một con ngựa. Anh mơ ước kiếm được nhiều tiền để trở thành một bai (người rất giàu có).
Đánh số các năm từ \(0\) đến \(N-1\) theo thứ tự thời gian, nên năm \(N-1\) là năm gần đây nhất. Thời tiết mỗi năm ảnh hưởng đến sự tăng trưởng của đàn ngựa. Với năm \(i\), Mansur nhớ hệ số tăng trưởng nguyên dương \(X[i]\): nếu bắt đầu năm với \(h\) con ngựa thì cuối năm, trước khi bán, sẽ có \(h \cdot X[i]\) con.
Ngựa chỉ được bán vào cuối năm. Với mỗi năm \(i\), Mansur nhớ số nguyên dương \(Y[i]\), là giá bán một con ngựa vào cuối năm đó. Sau mỗi năm, anh có thể bán số ngựa tùy ý trong đàn, mỗi con cùng giá \(Y[i]\).
Mansur muốn biết số tiền lớn nhất anh có thể có hiện nay nếu đã chọn thời điểm bán ngựa tốt nhất trong \(N\) năm. Bạn vinh dự là khách dự toi (ngày lễ) của Mansur và được anh nhờ trả lời câu hỏi này.
Trong buổi tối, trí nhớ của Mansur dần tốt hơn nên anh đưa ra \(M\) lần cập nhật. Mỗi lần thay đổi một giá trị \(X[i]\) hoặc \(Y[i]\), rồi anh lại hỏi số tiền lớn nhất có thể thu được. Các cập nhật có tính tích lũy: mỗi câu trả lời phải xét mọi cập nhật trước đó. Một giá trị \(X[i]\) hay \(Y[i]\) có thể được cập nhật nhiều lần.
Kết quả có thể rất lớn. Bạn chỉ cần trả về phần dư khi chia kết quả tối ưu cho \(10^9+7\).
Có \(N=3\) năm, với dữ liệu ban đầu:
| Năm | 0 | 1 | 2 |
|---|---|---|---|
| \(X\) | 2 | 1 | 3 |
| \(Y\) | 3 | 4 | 1 |
Mansur thu được nhiều tiền nhất bằng cách bán cả hai con ngựa vào cuối năm \(1\):
Sau đó có \(M=1\) cập nhật: đổi \(Y[1]\) thành \(2\). Dữ liệu trở thành:
| Năm | 0 | 1 | 2 |
|---|---|---|---|
| \(X\) | 2 | 1 | 3 |
| \(Y\) | 3 | 2 | 1 |
Một phương án tối ưu lúc này là bán một con sau năm \(0\), rồi ba con sau năm \(2\):
Cho \(N\), \(X\), \(Y\) và dãy cập nhật. Trước lần cập nhật đầu tiên và sau mỗi lần cập nhật, hãy tính số tiền lớn nhất Mansur có thể thu được, lấy phần dư modulo \(10^9+7\).
Trong C hoặc C++, cài đặt các hàm trong header dùng chung horses.h:
int init(int N, int X[], int Y[]);
int updateX(int pos, int val);
int updateY(int pos, int val);
Trong Java, cài đặt các phương thức sau trong lớp horses:
public int init(int N, int[] X, int[] Y)
public int updateX(int pos, int val)
public int updateY(int pos, int val)
Hàm init(N, X, Y) được gọi đầu tiên và đúng một lần:
N: số năm.X: mảng có \(N\) phần tử; X[i] là hệ số tăng trưởng năm \(i\), với \(0 \le i \le N-1\).Y: mảng có \(N\) phần tử; Y[i] là giá bán một con ngựa sau năm \(i\), với \(0 \le i \le N-1\).init kết thúc, X và Y vẫn hợp lệ; bạn có thể thay đổi nội dung của chúng nếu muốn.Hàm updateX(pos, val) thay đổi X[pos] thành val; hàm updateY(pos, val) thay đổi Y[pos] thành val. Trong cả hai hàm, \(0 \le \texttt{pos} \le N-1\). Mỗi hàm trả về số tiền lớn nhất có thể thu được sau cập nhật đó, modulo \(10^9+7\).
Mọi giá trị ban đầu và sau cập nhật của \(X[i]\), \(Y[i]\) đều thuộc đoạn \([1,10^9]\). Sau init, chương trình chấm gọi updateX và updateY tổng cộng \(M\) lần.
Chỉ nộp phần cài đặt hàm, không viết main. C và C++ đều dùng #include "horses.h"; LQDOJ cung cấp cùng tên header cho cả hai ngôn ngữ. Java dùng lớp horses, không viết phương thức main.
Mỗi subtask được trọn điểm nếu tất cả test của subtask đều đúng, nếu không được \(0\) điểm. Test mẫu là pretest \(0\) điểm.
| Subtask | Điểm | \(N\) | \(M\) | Ràng buộc bổ sung |
|---|---|---|---|---|
| 1 | 17 | \(1 \le N \le 10\) | \(M=0\) | \(X[i],Y[i] \le 10\) và \(X[0] \cdot X[1] \cdots X[N-1] \le 1000\). |
| 2 | 17 | \(1 \le N \le 1000\) | \(0 \le M \le 1000\) | Không có. |
| 3 | 20 | \(1 \le N \le 500000\) | \(0 \le M \le 100000\) | \(X[i] \ge 2\) trong init và val \(\ge 2\) trong updateX. |
| 4 | 23 | \(1 \le N \le 500000\) | \(0 \le M \le 10000\) | Không có. |
| 5 | 23 | \(1 \le N \le 500000\) | \(0 \le M \le 100000\) | Không có. |
Chương trình chấm mẫu đọc tệp horses.in:
N.X[0] ... X[N-1].Y[0] ... Y[N-1].M.type pos val; type=1 tương ứng với updateX, type=2 tương ứng với updateY.Chương trình in giá trị trả về của init, tiếp theo là giá trị trả về của từng lần gọi updateX hoặc updateY, mỗi giá trị trên một dòng. Grader trên LQDOJ dùng đầu vào/đầu ra chuẩn thay cho tệp, giữ nguyên giao diện hàm.
Dữ liệu vào:
3
2 1 3
3 4 1
1
2 1 2
Kết quả:
8
6Aizhan có dãy \(N\) số nguyên \(S[0],S[1],\ldots,S[N-1]\), gồm các số từ \(0\) đến \(N-1\), mỗi số xuất hiện đúng một lần. Cô muốn sắp xếp dãy tăng dần bằng cách đổi chỗ một số cặp phần tử. Bạn của cô là Ermek cũng sẽ đổi chỗ một số cặp phần tử, nhưng không nhất thiết giúp việc sắp xếp dễ hơn.
Hai người thay đổi dãy qua các vòng. Trong mỗi vòng, Ermek đổi chỗ trước, sau đó Aizhan thực hiện một phép đổi chỗ. Mỗi người chọn hai chỉ số hợp lệ rồi đổi chỗ các phần tử ở hai chỉ số đó. Hai chỉ số được phép bằng nhau; khi ấy một phần tử đổi chỗ với chính nó và dãy không thay đổi.
Aizhan biết Ermek không thực sự quan tâm đến việc sắp xếp \(S\) và biết chính xác những chỉ số mà Ermek sẽ chọn. Ermek dự định tham gia \(M\) vòng, đánh số từ \(0\) đến \(M-1\). Tại vòng \(i\), Ermek chọn hai chỉ số \(X[i]\) và \(Y[i]\).
Trước mỗi vòng, nếu thấy dãy đã tăng dần, Aizhan sẽ kết thúc toàn bộ quá trình. Cho dãy ban đầu và các chỉ số Ermek sẽ chọn, hãy tìm một dãy phép đổi chỗ mà Aizhan có thể dùng để sắp xếp \(S\). Trong một số subtask, dãy phép đổi chỗ phải ngắn nhất có thể. Đảm bảo có thể sắp xếp trong không quá \(M\) vòng.
Nếu dãy đã tăng dần ngay sau phép đổi chỗ của Ermek, Aizhan có thể đổi chỗ hai chỉ số bằng nhau, chẳng hạn \((0,0)\). Dãy vẫn tăng dần sau khi kết thúc vòng và Aizhan đạt mục tiêu. Nếu dãy ban đầu đã tăng dần, số vòng ít nhất là \(0\).
Dãy ban đầu là \(S=(4,3,2,1,0)\) và Ermek sẵn sàng thực hiện \(M=6\) phép đổi chỗ. Hai dãy chỉ số là \(X=(0,1,2,3,0,1)\) và \(Y=(1,2,3,4,1,2)\); các cặp của Ermek lần lượt là \((0,1)\), \((1,2)\), \((2,3)\), \((3,4)\), \((0,1)\), \((1,2)\).
Aizhan có thể đưa dãy về \((0,1,2,3,4)\) trong ba vòng bằng cách chọn lần lượt \((0,4)\), \((1,3)\), \((3,4)\):
| Vòng | Người thực hiện | Cặp chỉ số | Dãy sau thao tác |
|---|---|---|---|
| Ban đầu | \(4,3,2,1,0\) | ||
| 0 | Ermek | \((0,1)\) | \(3,4,2,1,0\) |
| 0 | Aizhan | \((0,4)\) | \(0,4,2,1,3\) |
| 1 | Ermek | \((1,2)\) | \(0,2,4,1,3\) |
| 1 | Aizhan | \((1,3)\) | \(0,1,4,2,3\) |
| 2 | Ermek | \((2,3)\) | \(0,1,2,4,3\) |
| 2 | Aizhan | \((3,4)\) | \(0,1,2,3,4\) |
Dãy ban đầu là \(S=(3,0,4,2,1)\) và Ermek sẵn sàng thực hiện \(M=5\) phép đổi chỗ. Các cặp chỉ số của Ermek lần lượt là \((1,1)\), \((4,0)\), \((2,3)\), \((1,4)\), \((0,4)\).
Aizhan có thể sắp xếp trong ba vòng, chẳng hạn chọn lần lượt \((1,4)\), \((4,2)\), \((2,2)\):
| Vòng | Người thực hiện | Cặp chỉ số | Dãy sau thao tác |
|---|---|---|---|
| Ban đầu | \(3,0,4,2,1\) | ||
| 0 | Ermek | \((1,1)\) | \(3,0,4,2,1\) |
| 0 | Aizhan | \((1,4)\) | \(3,1,4,2,0\) |
| 1 | Ermek | \((4,0)\) | \(0,1,4,2,3\) |
| 1 | Aizhan | \((4,2)\) | \(0,1,3,2,4\) |
| 2 | Ermek | \((2,3)\) | \(0,1,2,3,4\) |
| 2 | Aizhan | \((2,2)\) | \(0,1,2,3,4\) |
Cho \(S\), \(M\), \(X\), \(Y\), hãy tìm dãy phép đổi chỗ của Aizhan. Ở subtasks \(5\) và \(6\), phải tìm dãy ngắn nhất.
Trong C hoặc C++, cài đặt hàm trong header dùng chung sorting.h:
int findSwapPairs(int N, int S[], int M, int X[], int Y[], int P[], int Q[]);
Trong Java, cài đặt phương thức sau trong lớp sorting:
public int findSwapPairs(int N, int[] S, int M, int[] X, int[] Y, int[] P, int[] Q)
Hàm được chương trình chấm gọi đúng một lần:
N: độ dài dãy \(S\).S: mảng số nguyên chứa dãy ban đầu.M: số phép đổi chỗ Ermek dự định thực hiện.X, Y: hai mảng số nguyên dài \(M\). Tại vòng \(i\), với \(0 \le i \le M-1\), Ermek đổi chỗ các phần tử tại X[i], Y[i].P, Q: hai mảng số nguyên, mỗi mảng đã được cấp phát \(M\) phần tử, dùng để trả về một dãy phép đổi chỗ hợp lệ của Aizhan. Gọi \(R\) là độ dài dãy tìm được. Với \(0 \le i \le R-1\), ghi hai chỉ số Aizhan chọn ở vòng \(i\) vào P[i], Q[i].Chỉ nộp phần cài đặt hàm, không viết main. C và C++ đều dùng #include "sorting.h"; LQDOJ cung cấp cùng tên header cho cả hai ngôn ngữ. Java dùng lớp sorting, không viết phương thức main. Có thể trả về bất kỳ dãy phép đổi chỗ thỏa yêu cầu; bộ chấm kiểm tra tác dụng của các phép đổi chỗ, không so sánh nguyên văn với một đáp án mẫu.
Luôn tồn tại lời giải cần không quá \(M\) vòng. Mỗi subtask được trọn điểm nếu tất cả test của subtask đều đúng, nếu không được \(0\) điểm. Các mẫu là pretest \(0\) điểm.
| Subtask | Điểm | \(N\) | \(M\) | Ràng buộc bổ sung trên \(X\), \(Y\) | Yêu cầu đối với \(R\) |
|---|---|---|---|---|---|
| 1 | 8 | \(1 \le N \le 5\) | \(M=N^2\) | \(X[i]=Y[i]=0\) với mọi \(i\). | \(R \le M\). |
| 2 | 12 | \(1 \le N \le 100\) | \(M=30N\) | \(X[i]=Y[i]=0\) với mọi \(i\). | \(R \le M\). |
| 3 | 16 | \(1 \le N \le 100\) | \(M=30N\) | \(X[i]=0\), \(Y[i]=1\) với mọi \(i\). | \(R \le M\). |
| 4 | 18 | \(1 \le N \le 500\) | \(M=30N\) | Không có. | \(R \le M\). |
| 5 | 20 | \(6 \le N \le 2000\) | \(M=3N\) | Không có. | Nhỏ nhất có thể. |
| 6 | 26 | \(6 \le N \le 200000\) | \(M=3N\) | Không có. | Nhỏ nhất có thể. |
Chương trình chấm mẫu đọc tệp sorting.in:
N.S[0] ... S[N-1].M.X[i] Y[i], theo thứ tự \(i=0,\ldots,M-1\).Kết quả được in theo định dạng:
findSwapPairs.P[i] Q[i].Grader trên LQDOJ dùng đầu vào/đầu ra chuẩn thay cho tệp, giữ nguyên giao diện hàm.
Dữ liệu cho ví dụ 1:
5
4 3 2 1 0
6
0 1
1 2
2 3
3 4
0 1
1 2
Một kết quả hợp lệ:
3
0 4
1 3
3 4
Dữ liệu cho ví dụ 2:
5
3 0 4 2 1
5
1 1
4 0
2 3
1 4
0 4
Một kết quả hợp lệ:
3
1 4
4 2
2 2Kazakhstan có \(N\) thị trấn nhỏ, đánh số từ \(0\) đến \(N-1\), và một số lượng chưa biết các thành phố lớn. Các thị trấn nhỏ và thành phố lớn được gọi chung là các đô thị.
Tất cả đô thị được nối bởi một mạng đường cao tốc hai chiều duy nhất. Mỗi đường nối hai đô thị khác nhau; giữa một cặp đô thị có nhiều nhất một đường nối trực tiếp. Với mỗi cặp đô thị \(a\), \(b\), có duy nhất một cách đi từ \(a\) đến \(b\) bằng các đường cao tốc mà không sử dụng đường nào quá một lần.
Mỗi thị trấn nhỏ nối trực tiếp với đúng một đô thị khác; mỗi thành phố lớn nối trực tiếp với ít nhất ba đô thị.
Hình sau minh họa mạng gồm \(11\) thị trấn nhỏ và \(7\) thành phố lớn. Thị trấn được vẽ bằng hình tròn, ghi nhãn số nguyên; thành phố được vẽ bằng hình vuông, ghi nhãn chữ cái.
Mỗi đường cao tốc có độ dài nguyên dương. Khoảng cách giữa hai đô thị là tổng độ dài nhỏ nhất của các đường cần đi qua để từ đô thị này tới đô thị kia.
Với thành phố lớn \(C\), gọi \(r(C)\) là khoảng cách từ \(C\) đến thị trấn nhỏ xa nó nhất. Thành phố lớn \(C\) là một hub nếu \(r(C)\) nhỏ nhất trong số tất cả các thành phố lớn. Ký hiệu \(R\) là khoảng cách từ một hub đến thị trấn nhỏ xa nó nhất; như vậy \(R\) là giá trị nhỏ nhất trong tất cả các \(r(C)\).
Trong hình, thị trấn xa thành phố \(a\) nhất là thị trấn \(8\), với
Thành phố \(g\) cũng có \(r(g)=17\); một thị trấn xa \(g\) nhất là thị trấn \(6\). Hub duy nhất là thành phố \(f\), với \(r(f)=16\), nên \(R=16\).
Loại bỏ một hub sẽ chia mạng thành nhiều thành phần liên thông. Hub là cân bằng nếu mỗi thành phần chứa không quá \(\lfloor N/2\rfloor\) thị trấn nhỏ. Chỉ đếm thị trấn nhỏ, không đếm thành phố lớn. Ký hiệu \(\lfloor x\rfloor\) là số nguyên lớn nhất không vượt quá \(x\).
Trong ví dụ, loại bỏ \(f\) tạo thành bốn thành phần có các tập thị trấn \(\{0,1,10\}\), \(\{2,3\}\), \(\{4,5,6,7\}\) và \(\{8,9\}\). Không thành phần nào có quá \(\lfloor 11/2\rfloor=5\) thị trấn nhỏ, nên \(f\) là hub cân bằng.
Ban đầu bạn chỉ biết \(N\), số thị trấn nhỏ; không biết số thành phố lớn hay cách bố trí đường cao tốc. Bạn chỉ có thể lấy thêm thông tin bằng cách hỏi khoảng cách giữa hai thị trấn nhỏ.
Cần xác định \(R\) trong mọi subtask. Với subtasks \(3\) đến \(6\), còn phải xác định có tồn tại hub cân bằng hay không.
Trong C hoặc C++, cài đặt hàm sau trong header dùng chung towns.h:
int hubDistance(int N, int sub);
Chương trình chấm cung cấp hàm:
int getDistance(int i, int j);
Trong Java, cài đặt phương thức trong lớp towns:
public int hubDistance(int N, int sub)
Gọi phương thức do chương trình chấm cung cấp qua grader.lib.getDistance(i, j):
public static int getDistance(int i, int j)
Trong một lần chạy, chương trình chấm xét nhiều test, tối đa \(40\) test. Với mỗi test, hubDistance được gọi đúng một lần. Phải khởi tạo lại mọi biến cần thiết ở mỗi lần gọi.
N: số thị trấn nhỏ.sub: số hiệu subtask, như bảng bên dưới.sub bằng \(1\) hoặc \(2\), có thể trả về \(R\) hoặc \(-R\).sub lớn hơn \(2\), phải trả về \(R\) khi có hub cân bằng, và \(-R\) khi không có.getDistance(i, j) trả về khoảng cách giữa hai thị trấn nhỏ \(i\) và \(j\). Nếu \(i=j\) thì trả về \(0\); nếu đối số không hợp lệ cũng trả về \(0\). Mỗi lần gọi vẫn được tính vào giới hạn truy vấn.Chỉ nộp phần cài đặt hàm, không viết main. C và C++ đều dùng #include "towns.h"; LQDOJ cung cấp cùng tên header cho cả hai ngôn ngữ. Java dùng lớp towns, không viết phương thức main. Không đọc trực tiếp ma trận khoảng cách bí mật; chỉ dùng getDistance để lấy thông tin.
Trong mỗi test:
Số lần gọi getDistance bị giới hạn theo subtask. Nếu vượt giới hạn, chương trình bị dừng và test được xem là trả lời sai. Mỗi subtask được trọn điểm nếu tất cả test của subtask đều đúng, nếu không được \(0\) điểm. Test mẫu là pretest \(0\) điểm.
| Subtask | Điểm | Số truy vấn tối đa | Phải xác định hub cân bằng | Ràng buộc bổ sung |
|---|---|---|---|---|
| 1 | 13 | \(N(N-1)/2\) | Không | Không có. |
| 2 | 12 | \(\lceil 7N/2\rceil\) | Không | Không có. |
| 3 | 13 | \(N(N-1)/2\) | Có | Không có. |
| 4 | 10 | \(\lceil 7N/2\rceil\) | Có | Mỗi thành phố lớn nối trực tiếp với đúng ba đô thị. |
| 5 | 13 | \(5N\) | Có | Không có. |
| 6 | 39 | \(\lceil 7N/2\rceil\) | Có | Không có. |
Ký hiệu \(\lceil x\rceil\) là số nguyên nhỏ nhất lớn hơn hoặc bằng \(x\).
Số hiệu subtask là một phần của dữ liệu vào; chương trình chấm mẫu thay đổi hành vi theo số hiệu đó. Chương trình đọc tệp towns.in theo định dạng:
Đề chính thức mô tả chương trình chấm mẫu in giá trị trả về của hubDistance và số truy vấn trên hai dòng riêng biệt. Mã grader thực tế trong gói chính thức chỉ in giá trị trả về; grader LQDOJ giữ cách in này, kiểm soát số truy vấn bên trong và chuyển phần đọc/ghi sang đầu vào/đầu ra chuẩn.
Dữ liệu tương ứng với hình trên:
1 1
11
0 17 18 20 17 12 20 16 23 20 11
17 0 23 25 22 17 25 21 28 25 16
18 23 0 12 21 16 24 20 27 24 17
20 25 12 0 23 18 26 22 29 26 19
17 22 21 23 0 9 21 17 26 23 16
12 17 16 18 9 0 16 12 21 18 11
20 25 24 26 21 16 0 10 29 26 19
16 21 20 22 17 12 10 0 25 22 15
23 28 27 29 26 21 29 25 0 21 22
20 25 24 26 23 18 26 22 21 0 19
11 16 17 19 16 11 19 15 22 19 0
Một kết quả hợp lệ của grader trong gói đính kèm và trên LQDOJ:
16
Định dạng ma trận này khác với việc liệt kê các đường cao tốc. Bạn được phép sửa chương trình chấm mẫu để dùng định dạng đầu vào khác khi thử chương trình của mình.