Tôi tái tạo thuật toán của tôi từ here, nơi logic của nó được giải thích:
dp[i, j] = same as before num[i] = how many subsequences that end with i (element, not index this time)
have a certain length
for i = 1 to n do dp[i, 1] = 1
for p = 2 to k do // for each length this time num = {0}
for i = 2 to n do
// note: dp[1, p > 1] = 0
// how many that end with the previous element
// have length p - 1
num[ array[i - 1] ] += dp[i - 1, p - 1] *1*
// append the current element to all those smaller than it
// that end an increasing subsequence of length p - 1,
// creating an increasing subsequence of length p
for j = 1 to array[i] - 1 do *2*
dp[i, p] += num[j]
Bạn có thể tối ưu hóa *1*
và *2*
bằng cách sử dụng cây phân khúc hoặc cây được lập chỉ mục nhị phân. Những điều này sẽ được sử dụng để xử lý một cách hiệu quả các hoạt động sau đây trên mảng num
:
- Với
(x, v)
thêm v
để num[x]
(thích hợp cho *1*
);
- Cho
x
, tìm số tiền num[1] + num[2] + ... + num[x]
(có liên quan đến *2*
).
Đây là những vấn đề tầm thường cho cả hai cấu trúc dữ liệu.
Lưu ý: Điều này sẽ có độ phức tạp O(n*k*log S)
, trong đó S
là giới hạn trên trên các giá trị trong mảng của bạn. Điều này có thể hoặc có thể không đủ tốt. Để làm cho nó O(n*k*log n)
, bạn cần phải bình thường hóa các giá trị của mảng của bạn trước khi chạy thuật toán trên. Bình thường hóa có nghĩa là chuyển đổi tất cả các giá trị mảng của bạn thành các giá trị nhỏ hơn hoặc bằng n
. Vì vậy, đây:
5235 223 1000 40 40
trở thành:
4 2 3 1 1
Điều này có thể được thực hiện với một loại (giữ các chỉ số ban đầu).
tâm hiển thị mã bạn thấy có độ phức tạp O (n * k * log (n))? – taocp
Liên kết bộ mã hóa hàng đầu hiện đã được sửa. Bạn có thể tìm thấy nó ở đó. –
Sẽ dễ dàng hơn khi nghĩ về điều này mà không cần phải làm điều đó với BIT ngay lập tức. Tôi giải thích cách làm tại đây: http://stackoverflow.com/questions/15057591/how-to-find-the-total-number-of-increasing-sub-sequences-of-certain-length-with/15058391#15058391 – IVlad