Hướng dẫn cho Python Basic Contest #01 - Lưu trữ dữ liệu (Python only)


Chỉ sử dụng khi thực sự cần thiết như một cách tôn trọng tác giả và người viết hướng dẫn này.

Chép code từ bài hướng dẫn để nộp bài là hành vi có thể dẫn đến khóa tài khoản.

Authors: Sunlight

Lời giải
Subtask 1: n \le 10
  • Subtask này có thể được giải bằng thuật toán gốc trong sách giáo khoa (sinh tất cả các trường hợp). Bạn chỉ cần cài đúng như sách (chỉnh sửa một tí vì chúng mình không yêu cầu truy vết) là AC subtask này.

Độ phức tạp: O(3^n \times n).

Subtask 2: n \le 16
  • Ta có một nhận xét sau: nếu tồn tại một cách lưu k file bất kỳ vào hai ổ đĩa, thì luôn tồn tại một cách lưu k file có dung lượng nhỏ nhất vào hai ổ đĩa này. (Ví dụ: xét các file có kích thước lần lượt là 1, 2, 3, 4, 5, nếu ta tìm được cách lưu các file 1, 2, 4, 5 vào hai ổ đĩa thì chắc chắn sẽ tìm được cách lưu các file 1, 2, 3, 4 vào các ổ đĩa) Chứng minh của nhận xét này xin dành cho các bạn đọc.
  • Với nhận xét này, ta chỉ cần quan tâm đến việc tối đa hoá số k, sao cho tồn tại cách lưu k file dữ liệu có kích thước nhỏ nhất vào hai ổ đĩa. Ta sẽ thử các giá trị k tăng dần đến khi không tồn tại phương án thoả mãn. Với mỗi giá trị k, ta đệ quy quay lui để sinh ra toàn bộ các cách lưu k file vào một trong hai đĩa.

Độ phức tạp: O(2^n \times n).

Subtask 3: n, d, s_i \le 128
  • Ta xét một ý tưởng đệ quy tổng quát khá tự nhiên: F(i, j, k) là số lượng file lớn nhất có thể được lưu, với điều kiện các file này có vị trí trong đoạn [1, i] (nếu muốn lưu thêm file thì phải lưu các file có vị trí từ i + 1 trở lên), tổng kích thước các file đã lưu trong ổ đĩa thứ nhất là j và tổng kích thước các file lưu trong ổ cứng thứ hai là k.
  • Ta có thể tìm được công thức tính F(i, j, k) như sau: F(i, j, k) = max(F(i - 1, j - s_i, k) + 1, F(i - 1, j, k), F(i - 1, j, k - s_i) + 1) tương ứng với các trường hợp lưu file thứ i vào ổ đĩa thứ nhất, không lưu file thứ i và lưu file thứ i vào ổ đĩa thứ hai.
  • Từ công thức truy hồi, ta có thể thực hiện đệ quy có nhớ để tính các giá trị F(i, j, k). Kết quả sẽ là max(F(n, u, v)) với mọi u \le dv \le d. Khi cài đặt, có thể dùng mảng ba chiều thay cho việc dùng cấu trúc dữ liệu dictionary như trong sách giáo khoa để lưu các giá trị nhớ, và cần chú ý các trường hợp cơ sở (i = 0; j < 0; ...).

Độ phức tạp: O(d^2 \times n).

Subtask 4: Không có giới hạn gì thêm
  • Từ ý tưởng của subtask 3 và nhận xét của subtask 2, ta có thể giảm số tham số của hàm F theo hướng như sau:
    • Đầu tiên, sắp xếp dãy s theo thứ tự tăng dần.
    • Gọi F(i, j) là trạng thái có hay không cách để lưu i file đầu tiên vào hai ổ đĩa, trong đó tổng kích thước các file trong ổ đĩa thứ nhất là j và ổ đĩa thứ hai lưu phần còn lại. Có thể ký hiệu F(i, j) = 0 nếu không tồn tại cách xếp và F(i, j) = 1 nếu tồn tại.
    • Ta thấy rằng F(i, j) = max(F(i - 1, j), F(i - 1, j - s_i)), tương ứng với việc lưu hay không lưu file thứ i vào ổ đĩa thứ nhất. Chúng ta cần tìm số k lớn nhất để max(F(k, j)) = 1 với mọi s_1 + s_2 + ... + s_k - d \le j \le d.
  • Đến đây, các bạn có thể cài đặt đệ quy có nhớ như trong subtask 3, với những lưu ý tương tự.

Độ phức tạp: O(d \times n).



Bình luận

Không có bình luận nào.