Editorial for Dãy hoán vị


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.

Author: Yunan

Subtask 1: Xây dựng dãy số Q với Q_{P_i}=i với mọi 1 \le i \le N. Khi đó, dãy Q cũng là một dãy hoán vị và ta có thể hoán đổi giá trị của Q_iQ_j (i < j) nếu j-i = 1|Q_i-Q_j| \ge K, hay nói cách khác, ta có thể hoán đổi hai phần tử liền kề Q_iQ_{i+1} nếu |Q_i-Q_{i+1}| \ge K. Ta có nhận xét sau:

Nhận xét 1: Cho dãy hoán vị R độ dài N. Với mọi cặp số (x,y) thỏa mãn |x-y| < K, gọi ab là hai chỉ số thỏa mãn Q_a=xQ_b=y, gọi cd là hai chỉ số thỏa mãn R_c=xR_d=y. Khi đó, điều kiện cần và đủ để dãy Q có thể biến đổi thành dãy R(a<bc<d) hoặc (a>bc>d).

Từ đó, ta có thể kiểm tra tất cả các hoán vị R độ dài N (tổng cộng N! dãy hoán vị), với mỗi hoán vị R, kiểm tra xem dãy Q có thể biến đổi thành dãy R hay không từ nhận xét trên (việc kiểm tra có thể thực hiện trong O(N)), nếu có thể biến đổi, xây dựng dãy Z với Z_{R_i}=i (1 \le i \le N). Đáp án là dãy số có thứ tự từ điển nhỏ nhất trong số các dãy Z tìm được.

Độ phức tạp O(N.N!)

Subtask 2: Từ việc xây dựng dãy Q với Q_{P_i}=i với mọi 1 \le i \le N, ta có nhận xét mở rộng từ nhận xét 1 như sau:

Nhận xét 2: Cho dãy hoán vị A độ dài N. Với mọi cặp số (x,y) thỏa mãn |x-y| < K, khi đó, điều kiện cần và đủ để dãy P có thể biến đổi thành dãy A(P_x<P_yA_x<A_y) hoặc (P_x>P_yA_x>A_y).

Từ nhận xét trên, ta có thể xem bài toán ban đầu trở thành một bài toán đồ thị như sau:

Bài toán: Cho dãy hoán vị P độ dài N. Xây dựng một đồ thị gồm N đỉnh bằng cách: thêm cạnh nối một chiều từ đỉnh i đến đỉnh j nếu |i-j| < KP_i<P_j. Tìm một mảng label có thứ tự từ điển nhỏ nhất thỏa mãn: với mọi cạnh từ i đến j thì label_i<label_j. (Bài toán sắp xếp Topo)

Từ việc phát biểu bài toán như trên, đỉnh có bậc vào bằng 0 là đỉnh i thỏa mãn: P_i đạt giá trị nhỏ nhất trong khoảng [i-k+1,i+k-1], từ đó có thể tìm kiếm đỉnh i trong O(N). Việc xây dựng mảng label có thể thực hiện như sau:

  • Bước 1: Gọi v là giá trị để gán cho mảng label, ban đầu v=1.
  • Bước 2: Tìm đỉnh i nhỏ nhất là đỉnh có bậc vào bằng 0 và gán label_i=v.
  • Bước 3: Xóa đỉnh i và các cạnh nối từ i khỏi đồ thị.
  • Bước 4: Tăng giá trị v=v+1 và quay lại bước 2.

Độ phức tạp: O(N^2)

Subtask 3: Việc tìm kiếm đỉnh có bậc vào bằng 0 và xóa đỉnh khỏi đồ thị có thể thực hiện với cấu trúc Segment Tree với các thao tác cập nhật điểm và truy vấn đoạn. Bài toán có thể giải quyết với độ phức tạp O(N.log(N)).


Comments