👤 Writter: @CQTshadow
👥 Contributor: @SPyofgame
📋 Content:
Nhận xét
- Bài toán tưởng chừng khá quen thuộc, nhưng nếu code không cẩn thận thì sẽ vẫn bị vì test khá mạnh.
- Có rất nhiều cách để giải quyết bài toán này, ở đây tôi sẽ cung cấp cho các bạn cách làm sử dụng tập hợp.
Hướng dẫn
I. Giải quyết bài toán
1. Bản chất
- Bản chất chính, ta sẽ chia tập hợp đề bài của ta thành và duy trì tập hợp đó sao cho phần tử lớn nhất của tập hợp nhỏ hơn là của chúng ta :
- Giả sử tập hợp của chúng ta là
- Tập hợp : Lưu trữ các phần tử có vị trí thuộc khoảng
- Tập hợp : Lưu trữ các phần tử có vị trí thuộc khoảng
Để duy trì như yêu cầu, ta chỉ cần đảm bảo
2. Cài đặt
- Ta có thể dùng CTDL hoặc bất kỳ CTDL nào phù hợp với cách cài đặt.
a. Thao Tác Cân Bằng
- Như đã nói, ta cần duy trì sự cân bằng của tập hợp trên, do đó chỉ có trường hợp sai cần phải thay đổi :
- Trường hợp 1 :
Khi đó ta lấy phần tử lớn nhất ở tập hợp thêm vào tập hợp
- Trường hợp 2 :
Khi đó ta lấy phần tử bé nhất ở tập hợp thêm vào tập hợp
- Ta sẽ thêm thao tác này sau mọi thao tác thay đổi khác.
b. Thao Tác Thêm
- Ta cần xác định sẽ thêm phần tử mới vào tập hợp nào.
- Gọi là trung vị hiện tại của chúng ta, như đã nói nó sẽ là phần tử lớn nhất của tập hợp .
- Khi đó như cách ta sắp xếp hai tập hợp:
- Nếu phần tử có giá trị lớn hơn
Ta thêm nó vào tập hợp .
- Ngược lại
Ta thêm nó vào tập hợp .
Lưu ý : Nhớ xét riêng trường hợp rỗng
c. Thao Tác Xóa
- Ta có thể đơn giản sử dụng các lệnh tìm kiếm có sẵn ở trong CTDL đang sử dụng để tìm phần tử cần xóa xuất hiện ở đâu trong tập hợp sau đó xóa nó.
d. Thao Tác Tìm Trung Vị
- Ta chỉ cần gọi phần tử lớn nhất của tập hợp .
II. Cải Tiến
- Tưởng chừng như cách giải quyết trên đã đủ để AC, nhưng test lại đủ mạnh để khiến cho ta bị TLE, do đó ta cần các cải tiến.
1. Cải Tiến Thao Tác Xóa
- Nhìn nhận điều đặc biệt mà bài toán cho ta, ta thấy số mà đề yêu cầu xóa luôn tồn tại trong tập hợp Ta có thể lưu lại và xóa đi các phần tử cần xóa sau.
- Thật vậy, khi ta đã xác định phần tử giá trị nằm ở tập hợp nào, thì ta chỉ cần ghi nợ phần tử đó vào tập hợp, và trong các quá trình thao tác trong tương lai, nếu ta phát hiện phần tử đáng ra đã bị xóa thì ta sẽ xóa nó đi mà không ảnh hưởng tới các thao tác khác.
- Mục đích chính của việc lưu nợ này lại là vì ta sẽ đợi các phần tử cần xóa mà hiện tại đang ở giữa đâu đó trong tập hợp chính (khiến việc xóa mất ) xuất hiện ở đầu tập hợp (việc xóa chỉ mất )
- Ta sẽ ghi nợ bằng cách tạo một tập hợp với thứ tự sắp xếp tương tự tập hợp ta đang nợ, và các tập hợp này sẽ chỉ lưu đúng các giá trị chưa được xóa, và sau mọi thao tác thay đổi, ta sẽ gọi thao tác trả nợ này ra để xem xem có phần tử nào cần xóa đã xuất hiện ở hai đầu tập hợp hay chưa, và nếu có thì xóa chúng đi.
Lưu ý : Ta sẽ cần phải có một giá trị quản lý riêng ở mỗi tập hợp, vì nếu gọi thao tác thì sẽ sai vì nó sẽ bao gồm cả phần tử "đáng ra đã bị xóa" bị tính vào.
2. Cải Tiến Xuất
- Một mẹo nhỏ khiến thời gian giảm đi đôi chút là ta sẽ lưu kết quả vào một mảng trước rồi mới xuất ra.
Code Minh Họa
Time:
Space:
SPyofgame Dynamic Median Template